Express qmlvideofx effect parameters declaratively

Each effect item now exposes a ListModel property which describes the
set of user-controllable parameters.  This model is used by the
ParameterPanel component to generate a ListView whose delegate displays
the parameter name and a slider.

Change-Id: Ib26877fe434d8b746ef621e0b4adbcbe1ed9aaa8
Reviewed-by: Michael Goddard <michael.goddard@nokia.com>
This commit is contained in:
Gareth Stockwell
2011-12-20 13:51:34 +00:00
committed by Qt by Nokia
parent febe398400
commit 9092b1ae46
29 changed files with 225 additions and 222 deletions

View File

@@ -90,7 +90,7 @@ Rectangle {
effectLoader.item.targetHeight = root.height effectLoader.item.targetHeight = root.height
updateSource() updateSource()
effectLoader.item.source = theSource effectLoader.item.source = theSource
divider.visible = effectLoader.item.supportsDivider divider.visible = effectLoader.item.divider
updateDivider() updateDivider()
} }
@@ -101,7 +101,7 @@ Rectangle {
} }
function updateDivider() { function updateDivider() {
if (effectLoader.item && effectLoader.item.supportsDivider) if (effectLoader.item && effectLoader.item.divider)
effectLoader.item.dividerValue = divider.value effectLoader.item.dividerValue = divider.value
} }

View File

@@ -43,8 +43,9 @@ import QtQuick 2.0
ShaderEffect { ShaderEffect {
property variant source property variant source
property int numParameters: 0 property ListModel parameters: ListModel { }
property bool supportsDivider: false property bool divider: true
property real dividerValue: 0.5
property real targetWidth: 0 property real targetWidth: 0
property real targetHeight: 0 property real targetHeight: 0
property string fragmentShaderFilename property string fragmentShaderFilename

View File

@@ -42,13 +42,15 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 1 ListElement {
property bool supportsDivider: true name: "grid spacing"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real dividerValue: 0.5 property real grid: parameters.get(0).value * 10
property real grid: 10.0 * param1Value
property real step_x: 0.0015625 property real step_x: 0.0015625
property real step_y: targetHeight ? (step_x * targetWidth / targetHeight) : 0.0 property real step_y: targetHeight ? (step_x * targetWidth / targetHeight) : 0.0

View File

@@ -42,12 +42,15 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 1 ListElement {
property bool supportsDivider: true name: "threshold"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real dividerValue: 0.5 property real threshold: parameters.get(0).value
fragmentShaderFilename: "shaders/blackandwhite.fsh" fragmentShaderFilename: "shaders/blackandwhite.fsh"
} }

View File

@@ -42,11 +42,5 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect
property int numParameters: 0
property bool supportsDivider: true
property real dividerValue: 0.5
fragmentShaderFilename: "shaders/emboss.fsh" fragmentShaderFilename: "shaders/emboss.fsh"
} }

View File

@@ -44,23 +44,25 @@
import QtQuick 2.0 import QtQuick 2.0
Item { Item {
id: root id: root
property bool divider: true
property real dividerValue: 0.5
property ListModel parameters: ListModel {
ListElement {
name: "radius"
value: 0.5
}
}
property alias targetWidth: verticalShader.targetWidth property alias targetWidth: verticalShader.targetWidth
property alias targetHeight: verticalShader.targetHeight property alias targetHeight: verticalShader.targetHeight
property alias source: verticalShader.source property alias source: verticalShader.source
// Constant properties which must be supported by every effect
property int numParameters: 1
property bool supportsDivider: true
property real param1Value: 0.5
property real dividerValue: 0.5
Effect { Effect {
id: verticalShader id: verticalShader
anchors.fill: parent anchors.fill: parent
property real dividerValue: parent.dividerValue property real dividerValue: parent.dividerValue
property real blurSize: 4.0 * parent.param1Value / targetHeight property real blurSize: 4.0 * parent.parameters.get(0).value / targetHeight
fragmentShaderFilename: "shaders/gaussianblur_v.fsh" fragmentShaderFilename: "shaders/gaussianblur_v.fsh"
} }
@@ -68,7 +70,7 @@ id: root
id: horizontalShader id: horizontalShader
anchors.fill: parent anchors.fill: parent
property real dividerValue: parent.dividerValue property real dividerValue: parent.dividerValue
property real blurSize: 4.0 * parent.param1Value / targetWidth property real blurSize: 4.0 * parent.parameters.get(0).value / targetWidth
fragmentShaderFilename: "shaders/gaussianblur_h.fsh" fragmentShaderFilename: "shaders/gaussianblur_h.fsh"
source: horizontalShaderSource source: horizontalShaderSource

View File

@@ -42,11 +42,5 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect
property int numParameters: 0
property bool supportsDivider: true
property real dividerValue: 0.5
fragmentShaderFilename: "shaders/glow.fsh" fragmentShaderFilename: "shaders/glow.fsh"
} }

View File

@@ -42,16 +42,20 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 2 ListElement {
property bool supportsDivider: true name: "hue"
value: 0.5
}
ListElement {
name: "width"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real param2Value: 0.5 property real targetHue: parameters.get(0).value * 360
property real dividerValue: 0.5 property real windowWidth: parameters.get(1).value * 60
property real targetHue: 360.0 * param1Value
property real windowWidth: 60.0 * param2Value
fragmentShaderFilename: "shaders/isolate.fsh" fragmentShaderFilename: "shaders/isolate.fsh"
} }

View File

@@ -43,20 +43,25 @@ import QtQuick 2.0
Effect { Effect {
id: root id: root
divider: false
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 2 ListElement {
property bool supportsDivider: false name: "radius"
value: 0.5
property real param1Value: 0.5 }
property real radius: 200 * param1Value ListElement {
name: "diffraction"
property real param2Value: 0.5 value: 0.5
property real diffractionIndex: param2Value }
}
property real posX: -1 property real posX: -1
property real posY: -1 property real posY: -1
// Transform slider values, and bind result to shader uniforms
property real radius: parameters.get(0).value * 100
property real diffractionIndex: parameters.get(1).value
onTargetWidthChanged: if (posX == -1) posX = targetWidth / 2 onTargetWidthChanged: if (posX == -1) posX = targetWidth / 2
onTargetHeightChanged: if (posY == -1) posY = targetHeight / 2 onTargetHeightChanged: if (posY == -1) posY = targetHeight / 2

View File

@@ -42,14 +42,16 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect divider: false
property int numParameters: 1 parameters: ListModel {
property bool supportsDivider: false ListElement {
name: "extent"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real dividerValue: 0.5 property real curlExtent: 1.0 - parameters.get(0).value
property real curlExtent: 1.0 - param1Value
fragmentShaderFilename: "shaders/pagecurl.fsh" fragmentShaderFilename: "shaders/pagecurl.fsh"
} }

View File

@@ -42,5 +42,5 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
divider: false
} }

View File

@@ -42,14 +42,15 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 1 ListElement {
property bool supportsDivider: true name: "granularity"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real dividerValue: 0.5 property real granularity: parameters.get(0).value * 20
property real granularity: param1Value * 20
fragmentShaderFilename: "shaders/pixelate.fsh" fragmentShaderFilename: "shaders/pixelate.fsh"
} }

View File

@@ -42,14 +42,16 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 1 ListElement {
property bool supportsDivider: true name: "gamma"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real dividerValue: 0.5 property real gamma: parameters.get(0).value
property real gamma: param1Value
property real numColors: 8.0 property real numColors: 8.0
fragmentShaderFilename: "shaders/posterize.fsh" fragmentShaderFilename: "shaders/posterize.fsh"

View File

@@ -42,20 +42,23 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 2 ListElement {
property bool supportsDivider: true name: "amplitude"
value: 0.5
}
ListElement {
name: "frequency"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real param2Value: 0.5 property real amplitude: parameters.get(0).value * 0.03
property real dividerValue: 0.5 property real n: parameters.get(1).value * 7
property real time: 0 property real time: 0
NumberAnimation on time { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 600 } NumberAnimation on time { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 600 }
property real amplitude: param1Value * 0.03
property real n: param2Value * 7
fragmentShaderFilename: "shaders/ripple.fsh" fragmentShaderFilename: "shaders/ripple.fsh"
} }

View File

@@ -42,11 +42,5 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect
property int numParameters: 0
property bool supportsDivider: true
property real dividerValue: 0.5
fragmentShaderFilename: "shaders/sepia.fsh" fragmentShaderFilename: "shaders/sepia.fsh"
} }

View File

@@ -42,14 +42,15 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 1 ListElement {
property bool supportsDivider: true name: "sharpness"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real dividerValue: 0.5 property real amount: parameters.get(0).value * 18
property real amount: 18.0 * param1Value
fragmentShaderFilename: "shaders/sharpen.fsh" fragmentShaderFilename: "shaders/sharpen.fsh"
} }

View File

@@ -43,15 +43,16 @@ import QtQuick 2.0
Effect { Effect {
id: root id: root
parameters: ListModel {
ListElement {
name: "amplitude"
value: 0.5
}
}
// Constant properties which must be supported by every effect // Transform slider values, and bind result to shader uniforms
property int numParameters: 1 property real granularity: parameters.get(0).value * 20
property bool supportsDivider: true property real weight: parameters.get(0).value
property real param1Value: 0.5
property real dividerValue: 0.5
property real granularity: param1Value * 20
property real centerX property real centerX
property real centerY property real centerY
@@ -75,7 +76,5 @@ Effect {
} }
} }
property real weight: param1Value
fragmentShaderFilename: "shaders/shockwave.fsh" fragmentShaderFilename: "shaders/shockwave.fsh"
} }

View File

@@ -42,15 +42,16 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 1 ListElement {
property bool supportsDivider: true name: "threshold"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real dividerValue: 0.5 property real mixLevel: parameters.get(0).value
property real targetSize: 250 - (200 * mixLevel) // TODO: fix ...
property real mixLevel: param1Value
property real targetSize: 250 - (200 * param1Value) // TODO: fix ...
property real resS: targetSize property real resS: targetSize
property real resT: targetSize property real resT: targetSize

View File

@@ -42,14 +42,15 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 1 ListElement {
property bool supportsDivider: true name: "threshold"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real dividerValue: 0.5 property real weight: parameters.get(0).value
property real weight: param1Value
fragmentShaderFilename: "shaders/sobeledgedetection2.fsh" fragmentShaderFilename: "shaders/sobeledgedetection2.fsh"
} }

View File

@@ -42,11 +42,5 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect
property int numParameters: 0
property bool supportsDivider: true
property real dividerValue: 0.5
fragmentShaderFilename: "shaders/tiltshift.fsh" fragmentShaderFilename: "shaders/tiltshift.fsh"
} }

View File

@@ -42,15 +42,16 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 1 ListElement {
property bool supportsDivider: true name: "threshold"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real dividerValue: 0.5 property real threshold: parameters.get(0).value
property real targetSize: 250 - (200 * threshold) // TODO: fix ...
property real threshold: param1Value
property real targetSize: 250 - (200 * param1Value) // TODO: fix ...
property real resS: targetSize property real resS: targetSize
property real resT: targetSize property real resT: targetSize

View File

@@ -42,11 +42,5 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect
property int numParameters: 0
property bool supportsDivider: true
property real dividerValue: 0.5
fragmentShaderFilename: "shaders/vignette.fsh" fragmentShaderFilename: "shaders/vignette.fsh"
} }

View File

@@ -42,11 +42,5 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect
property int numParameters: 0
property bool supportsDivider: true
property real dividerValue: 0.5
fragmentShaderFilename: "shaders/warhol.fsh" fragmentShaderFilename: "shaders/warhol.fsh"
} }

View File

@@ -42,14 +42,16 @@
import QtQuick 2.0 import QtQuick 2.0
Effect { Effect {
// Constant properties which must be supported by every effect parameters: ListModel {
property int numParameters: 1 ListElement {
property bool supportsDivider: true name: "amplitude"
value: 0.5
}
}
property real param1Value: 0.5 // Transform slider values, and bind result to shader uniforms
property real dividerValue: 0.5 property real amplitude: parameters.get(0).value * 0.05
property real amplitude: param1Value * 0.05
property real frequency: 20 property real frequency: 20
property real time: 0 property real time: 0

View File

@@ -44,44 +44,64 @@ import QtQuick 2.0
Rectangle { Rectangle {
id: root id: root
color: "transparent" color: "transparent"
height: numParameters * sliderHeight + (numParameters + 1) * spacing height: view.model.count * sliderHeight
visible: numParameters > 0
property color lineColor: "black" property color lineColor: "black"
property int numParameters: 1
property alias param1Value: slider1.value
property alias param2Value: slider2.value
property bool enabled: true
property real gripSize: 25 property real gripSize: 25
property real spacing: 10 property real spacing: 10
property real sliderHeight: 40 property real sliderHeight: 40
Slider { property ListModel model: ListModel { }
id: slider1
color: "white" Rectangle {
enabled: parent.enabled anchors.fill: parent
gripSize: root.gripSize color: "black"
height: sliderHeight opacity: 0.5
visible: enabled radius: 10
anchors { }
left: parent.left
right: parent.right Component {
bottom: (root.numParameters == 1) ? root.bottom : slider2.top id: editDelegate
margins: root.spacing
Rectangle {
id: delegate
width: parent.width
height: root.sliderHeight
color: "transparent"
Text {
id: text
text: name
color: "white"
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
}
font.pixelSize: 0.5 * parent.height
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
width: 150
}
Slider {
anchors {
top: parent.top
bottom: parent.bottom
left: text.right
leftMargin: 20
right: parent.right
rightMargin: 20
}
value: model.value
onValueChanged: view.model.setProperty(index, "value", value)
}
} }
} }
Slider { ListView {
id: slider2 id: view
color: "white" anchors.fill: parent
enabled: parent.enabled && root.numParameters >= 2 model: root.model
gripSize: root.gripSize delegate: editDelegate
height: sliderHeight
visible: enabled
anchors {
left: parent.left
right: parent.right
bottom: root.bottom
margins: root.spacing
}
} }
} }

View File

@@ -43,9 +43,10 @@ import QtQuick 2.0
Rectangle { Rectangle {
id: root id: root
color: "white" color: "transparent"
radius: 5 radius: 5
property alias value: grip.value property alias value: grip.value
property color fillColor: "white"
property color lineColor: "black" property color lineColor: "black"
property alias gripSize: grip.width property alias gripSize: grip.width
property alias enabled: mouseArea.enabled property alias enabled: mouseArea.enabled
@@ -57,7 +58,7 @@ Rectangle {
Rectangle { Rectangle {
anchors { fill: parent; margins: 1 } anchors { fill: parent; margins: 1 }
color: root.color color: root.fillColor
} }
} }
@@ -95,12 +96,12 @@ Rectangle {
Rectangle { Rectangle {
anchors { fill: parent; margins: 1 } anchors { fill: parent; margins: 1 }
radius: width/2 radius: width/2
color: root.color color: root.fillColor
} }
} }
function displayedColor() { function displayedColor() {
var tint = Qt.rgba(color.r, color.g, color.b, 0.25) var tint = Qt.rgba(fillColor.r, fillColor.g, fillColor.b, 0.25)
return enabled ? lineColor : Qt.tint(color, tint) return enabled ? lineColor : Qt.tint(fillColor, tint)
} }
} }

View File

@@ -94,15 +94,12 @@ Rectangle {
ParameterPanel { ParameterPanel {
id: parameterPanel id: parameterPanel
enabled: numParameters >= 1
numParameters: content.effect ? content.effect.numParameters : 0
anchors { anchors {
top: content.bottom
left: parent.left left: parent.left
bottom: parent.bottom bottom: parent.bottom
right: effectSelectionPanel.left
margins: 20
} }
width: content.width
onParam1ValueChanged: updateParameters()
} }
EffectSelectionPanel { EffectSelectionPanel {
@@ -117,7 +114,7 @@ Rectangle {
itemHeight: 40 itemHeight: 40
onEffectSourceChanged: { onEffectSourceChanged: {
content.effectSource = effectSource content.effectSource = effectSource
updateParameters() parameterPanel.model = content.effect.parameters
} }
} }
@@ -160,11 +157,6 @@ Rectangle {
performanceLoader.item.qmlFramePainted() performanceLoader.item.qmlFramePainted()
} }
function updateParameters() {
if (content.effect.numParameters >= 1)
content.effect.param1Value = parameterPanel.param1Value
}
function openImage() { function openImage() {
d.openFileType = "image" d.openFileType = "image"
showFileBrowser("../../images") showFileBrowser("../../images")

View File

@@ -71,7 +71,11 @@ Rectangle {
} }
onLoaded: { onLoaded: {
item.parent = root item.parent = root
item.anchors.fill = root item.anchors.top = root.top
item.anchors.topMargin = 100
item.anchors.left = root.left
item.anchors.right = root.right
item.anchors.bottom = root.verticalCenter
item.logging = root.perfMonitorsLogging item.logging = root.perfMonitorsLogging
item.displayed = root.perfMonitorsVisible item.displayed = root.perfMonitorsVisible
item.init() item.init()
@@ -92,15 +96,12 @@ Rectangle {
ParameterPanel { ParameterPanel {
id: parameterPanel id: parameterPanel
anchors { anchors {
left: parent.left; left: parent.left;
right: parent.right; right: parent.right;
margins: 10 margins: 10
} }
numParameters: content.effect.numParameters
y: parent.height y: parent.height
opacity: 0.75
gripSize: 40 gripSize: 40
states: [ states: [
@@ -125,10 +126,8 @@ Rectangle {
} }
] ]
enabled: content.effect.numParameters >= 1 && effectSelectionPanel.state != "shown" enabled: false
state: enabled ? "shown" : "baseState" state: enabled ? "shown" : "baseState"
onParam1ValueChanged: updateParameters()
onParam2ValueChanged: updateParameters()
} }
EffectSelectionPanel { EffectSelectionPanel {
@@ -168,8 +167,12 @@ Rectangle {
onEffectSourceChanged: { onEffectSourceChanged: {
content.effectSource = effectSource content.effectSource = effectSource
parameterPanel.numParameters = content.effect.numParameters if (content.effect.parameters.count) {
updateParameters() parameterPanel.model = content.effect.parameters
parameterPanel.enabled = true
} else {
parameterPanel.enabled = false
}
} }
onClicked: state = "baseState" onClicked: state = "baseState"
@@ -364,13 +367,6 @@ Rectangle {
performanceLoader.item.qmlFramePainted() performanceLoader.item.qmlFramePainted()
} }
function updateParameters() {
if (content.effect.numParameters >= 1)
content.effect.param1Value = parameterPanel.param1Value
if (content.effect.numParameters >= 2)
content.effect.param2Value = parameterPanel.param2Value
}
function openImage() { function openImage() {
fileOpenContainer.state = "baseState" fileOpenContainer.state = "baseState"
d.openFileType = "image" d.openFileType = "image"

View File

@@ -41,7 +41,7 @@
// Based on http://kodemongki.blogspot.com/2011/06/kameraku-custom-shader-effects-example.html // Based on http://kodemongki.blogspot.com/2011/06/kameraku-custom-shader-effects-example.html
uniform float param1Value; uniform float threshold;
uniform float dividerValue; uniform float dividerValue;
uniform sampler2D source; uniform sampler2D source;
@@ -54,7 +54,7 @@ void main()
vec4 orig = texture2D(source, uv); vec4 orig = texture2D(source, uv);
vec3 col = orig.rgb; vec3 col = orig.rgb;
float y = 0.3 *col.r + 0.59 * col.g + 0.11 * col.b; float y = 0.3 *col.r + 0.59 * col.g + 0.11 * col.b;
y = y < param1Value ? 0.0 : 1.0; y = y < threshold ? 0.0 : 1.0;
if (uv.x < dividerValue) if (uv.x < dividerValue)
gl_FragColor = qt_Opacity * vec4(y, y, y, 1.0); gl_FragColor = qt_Opacity * vec4(y, y, y, 1.0);
else else