summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Mardelle <jb@kdenlive.org>2016-09-25 20:35:58 (GMT)
committerJean-Baptiste Mardelle <jb@kdenlive.org>2016-09-25 20:35:58 (GMT)
commit71e11d7aa87b784a8e47c13b5211dcdcbc90930a (patch)
tree8959ee90cdf8bb40713bccbfbe9b0168fe63abfa
parent891fe44167e2f431d54dcfc133ff6d5775e3e679 (diff)
Reintroduce the much requested rotoscoping effect, now ported to qml
-rw-r--r--data/kdenlivemonitorrotoscene.qml169
-rw-r--r--src/monitor/monitor.cpp18
-rw-r--r--src/monitor/monitor.h1
-rw-r--r--src/monitor/qmlmanager.cpp17
-rw-r--r--src/monitor/qmlmanager.h1
-rw-r--r--src/onmonitoritems/rotoscoping/rotowidget.cpp46
-rw-r--r--src/onmonitoritems/rotoscoping/rotowidget.h4
7 files changed, 208 insertions, 48 deletions
diff --git a/data/kdenlivemonitorrotoscene.qml b/data/kdenlivemonitorrotoscene.qml
index 816e92e..b707775 100644
--- a/data/kdenlivemonitorrotoscene.qml
+++ b/data/kdenlivemonitorrotoscene.qml
@@ -20,10 +20,14 @@ Item {
onScaleyChanged: canvas.requestPaint()
onSourcedarChanged: refreshdar()
property bool iskeyframe : true
- property int requestedKeyFrame
- property var centerPoints: [Qt.point(120, 100), Qt.point(160, 100), Qt.point(180, 200), Qt.point(120, 200)]
- property var centerPointsTypes: [Qt.point(120, 100), Qt.point(160, 100), Qt.point(180, 200), Qt.point(120, 200)]
- onCenterPointsChanged: canvas.requestPaint()
+ property bool isDefined: false
+ property int requestedKeyFrame : -1
+ property int requestedSubKeyFrame : -1
+ // The coordinate points where the bezier curve passes
+ property var centerPoints : []
+ // The control points for the bezier curve points (2 controls points for each coordinate)
+ property var centerPointsTypes : []
+ onCenterPointsTypesChanged: checkDefined()
signal effectPolygonChanged()
signal addKeyframe()
signal seekToKeyframe()
@@ -33,6 +37,11 @@ Item {
canvas.requestPaint()
}
+ function checkDefined() {
+ root.isDefined = root.centerPointsTypes.length > 0
+ canvas.requestPaint()
+ }
+
Text {
id: fontReference
property int fontSize
@@ -60,22 +69,73 @@ Item {
ctx.strokeStyle = Qt.rgba(1, 0, 0, 0.5)
ctx.fillStyle = Qt.rgba(1, 0, 0, 0.5)
ctx.lineWidth = 2
+ if (root.centerPoints.length == 0) {
+ // no points defined yet
+ return
+ }
var p1 = convertPoint(root.centerPoints[0])
var startP = p1;
ctx.moveTo(p1.x, p1.y)
- ctx.fillRect(p1.x - handleSize, p1.y - handleSize, 2 * handleSize, 2 * handleSize);
- for (var i = 0; i < root.centerPoints.length - 1; i++) {
- p1 = convertPoint(root.centerPoints[i + 1])
- // Control points
- var c1 = convertPoint(root.centerPointsTypes[i])
- var c2 = convertPoint(root.centerPointsTypes[i + 1])
- ctx.bezierCurveTo(c1.x, c1.y, c2.x, c2.y, p1.x, p1.y);
+ if (!isDefined) {
ctx.fillRect(p1.x - handleSize, p1.y - handleSize, 2 * handleSize, 2 * handleSize);
- }
- if (root.centerPoints.length > 2) {
- var c1 = convertPoint(root.centerPointsTypes[root.centerPoints.length - 1])
- var c2 = convertPoint(root.centerPointsTypes[0])
- ctx.bezierCurveTo(c1.x, c1.y, c2.x, c2.y, startP.x, startP.y);
+ for (var i = 1; i < root.centerPoints.length; i++) {
+ p1 = convertPoint(root.centerPoints[i])
+ ctx.lineTo(p1.x, p1.y);
+ ctx.fillRect(p1.x - handleSize, p1.y - handleSize, 2 * handleSize, 2 * handleSize);
+ }
+ } else {
+ var c1; var c2
+ for (var i = 0; i < root.centerPoints.length; i++) {
+ p1 = convertPoint(root.centerPoints[i])
+ // Control points
+ var subkf = false
+ if (i == 0) {
+ c1 = convertPoint(root.centerPointsTypes[root.centerPointsTypes.length - 1])
+ if (root.requestedSubKeyFrame == root.centerPointsTypes.length - 1) {
+ subkf = true
+ }
+ } else {
+ c1 = convertPoint(root.centerPointsTypes[2*i - 1])
+ if (root.requestedSubKeyFrame == 2*i - 1) {
+ subkf = true
+ }
+ }
+ c2 = convertPoint(root.centerPointsTypes[2*i])
+ ctx.bezierCurveTo(c1.x, c1.y, c2.x, c2.y, p1.x, p1.y);
+ if (iskeyframe) {
+ if (subkf) {
+ ctx.fillStyle = Qt.rgba(1, 1, 0, 0.8)
+ ctx.fillRect(c1.x - handleSize/2, c1.y - handleSize/2, handleSize, handleSize);
+ ctx.fillStyle = Qt.rgba(1, 0, 0, 0.5)
+ } else {
+ ctx.fillRect(c1.x - handleSize/2, c1.y - handleSize/2, handleSize, handleSize);
+ }
+ if (root.requestedSubKeyFrame == 2 * i) {
+ ctx.fillStyle = Qt.rgba(1, 1, 0, 0.8)
+ ctx.fillRect(c2.x - handleSize/2, c2.y - handleSize/2, handleSize, handleSize);
+ ctx.fillStyle = Qt.rgba(1, 0, 0, 0.5)
+ } else {
+ ctx.fillRect(c2.x - handleSize/2, c2.y - handleSize/2, handleSize, handleSize);
+ }
+ c1 = convertPoint(root.centerPointsTypes[2*i + 1])
+ ctx.lineTo(c1.x, c1.y);
+ ctx.moveTo(p1.x, p1.y)
+ ctx.lineTo(c2.x, c2.y);
+ ctx.moveTo(p1.x, p1.y)
+ if (i == root.requestedKeyFrame) {
+ ctx.fillStyle = Qt.rgba(1, 1, 0, 0.8)
+ ctx.fillRect(p1.x - handleSize, p1.y - handleSize, 2 * handleSize, 2 * handleSize);
+ ctx.fillStyle = Qt.rgba(1, 0, 0, 0.5)
+ } else {
+ ctx.fillRect(p1.x - handleSize, p1.y - handleSize, 2 * handleSize, 2 * handleSize);
+ }
+ }
+ }
+ if (root.centerPoints.length > 2) {
+ var c1 = convertPoint(root.centerPointsTypes[root.centerPointsTypes.length - 1])
+ var c2 = convertPoint(root.centerPointsTypes[0])
+ ctx.bezierCurveTo(c1.x, c1.y, c2.x, c2.y, startP.x, startP.y);
+ }
}
ctx.stroke()
@@ -88,6 +148,7 @@ Item {
return Qt.point(x,y);
}
}
+
Rectangle {
id: frame
objectName: "referenceframe"
@@ -102,24 +163,71 @@ Item {
MouseArea {
id: global
objectName: "global"
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
width: root.width; height: root.height
property bool containsMouse
anchors.centerIn: root
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
+ onClicked: {
+ if (!root.isDefined) {
+ if (mouse.button == Qt.RightButton) {
+ // close shape, define control points
+ var p0; var p1; var p2
+ for (var i = 0; i < root.centerPoints.length; i++) {
+ p1 = root.centerPoints[i]
+ if (i == 0) {
+ p0 = root.centerPoints[root.centerPoints.length - 1]
+ } else {
+ p0 = root.centerPoints[i - 1]
+ }
+ if (i == root.centerPoints.length - 1) {
+ p2 = root.centerPoints[0]
+ } else {
+ p2 = root.centerPoints[i + 1]
+ }
+ var ctrl1 = Qt.point((p0.x - p1.x) / 5, (p0.y - p1.y) / 5);
+ var ctrl2 = Qt.point((p2.x - p1.x) / 5, (p2.y - p1.y) / 5);
+ root.centerPointsTypes.push(Qt.point(p1.x + ctrl1.x, p1.y + ctrl1.y))
+ root.centerPointsTypes.push(Qt.point(p1.x + ctrl2.x, p1.y + ctrl2.y))
+ }
+ root.isDefined = true;
+ root.effectPolygonChanged()
+ canvas.requestPaint()
+ } else {
+ var newPoint = Qt.point((mouseX - frame.x) / root.scalex, (mouseY - frame.y) / root.scaley);
+ root.centerPoints.push(newPoint)
+ canvas.requestPaint()
+ }
+ }
+ }
+
onDoubleClicked: {
root.addKeyframe()
}
onPositionChanged: {
if (root.iskeyframe == false) return;
- if (pressed && root.requestedKeyFrame >= 0) {
- root.centerPoints[root.requestedKeyFrame].x = (mouseX - frame.x) / root.scalex;
- root.centerPoints[root.requestedKeyFrame].y = (mouseY - frame.y) / root.scaley;
- canvas.requestPaint()
- root.effectPolygonChanged()
- } else {
+ if (isDefined && pressed) {
+ if (root.requestedKeyFrame >= 0) {
+ var xDiff = (mouseX - frame.x) / root.scalex - root.centerPoints[root.requestedKeyFrame].x
+ var yDiff = (mouseY - frame.y) / root.scaley - root.centerPoints[root.requestedKeyFrame].y
+ root.centerPoints[root.requestedKeyFrame].x += xDiff
+ root.centerPoints[root.requestedKeyFrame].y += yDiff
+ root.centerPointsTypes[root.requestedKeyFrame * 2].x += xDiff
+ root.centerPointsTypes[root.requestedKeyFrame * 2].y += yDiff
+ root.centerPointsTypes[root.requestedKeyFrame * 2 + 1].x += xDiff
+ root.centerPointsTypes[root.requestedKeyFrame * 2 + 1].y += yDiff
+ canvas.requestPaint()
+ root.effectPolygonChanged()
+ } else if (root.requestedSubKeyFrame >= 0) {
+ root.centerPointsTypes[root.requestedSubKeyFrame].x = (mouseX - frame.x) / root.scalex
+ root.centerPointsTypes[root.requestedSubKeyFrame].y = (mouseY - frame.y) / root.scaley
+ canvas.requestPaint()
+ root.effectPolygonChanged()
+ }
+ } else if (root.centerPoints.length > 0) {
for(var i = 0; i < root.centerPoints.length; i++)
{
var p1 = canvas.convertPoint(root.centerPoints[i])
@@ -134,10 +242,25 @@ Item {
return;
}
}
- if (root.requestedKeyFrame == -1) {
+ for(var i = 0; i < root.centerPointsTypes.length; i++)
+ {
+ var p1 = canvas.convertPoint(root.centerPointsTypes[i])
+ if (Math.abs(p1.x - mouseX) <= canvas.handleSize/2 && Math.abs(p1.y - mouseY) <= canvas.handleSize/2) {
+ if (i == root.requestedSubKeyFrame) {
+ containsMouse = true;
+ return;
+ }
+ root.requestedSubKeyFrame = i
+ canvas.requestPaint()
+ containsMouse = true;
+ return;
+ }
+ }
+ if (root.requestedKeyFrame == -1 && root.requestedSubKeyFrame == -1) {
return;
}
root.requestedKeyFrame = -1
+ root.requestedSubKeyFrame = -1
containsMouse = false;
canvas.requestPaint()
}
diff --git a/src/monitor/monitor.cpp b/src/monitor/monitor.cpp
index 29a4d31..0252561 100644
--- a/src/monitor/monitor.cpp
+++ b/src/monitor/monitor.cpp
@@ -1565,6 +1565,24 @@ QVariantList Monitor::effectPolygon() const
return root->property("centerPoints").toList();
}
+QVariantList Monitor::effectRoto() const
+{
+ QQuickItem *root = m_glMonitor->rootObject();
+ if (!root) {
+ return QVariantList();
+ }
+ QVariantList points = root->property("centerPoints").toList();
+ QVariantList controlPoints = root->property("centerPointsTypes").toList();
+ // rotoscoping effect needs a list of
+ QVariantList mix;
+ for (int i = 0; i < points.count(); i++) {
+ mix << controlPoints.at(2 * i);
+ mix << points.at(i);
+ mix << controlPoints.at(2 * i + 1);
+ }
+ return mix;
+}
+
void Monitor::setEffectKeyframe(bool enable)
{
QQuickItem *root = m_glMonitor->rootObject();
diff --git a/src/monitor/monitor.h b/src/monitor/monitor.h
index 3e933e6..f90e6c6 100644
--- a/src/monitor/monitor.h
+++ b/src/monitor/monitor.h
@@ -129,6 +129,7 @@ public:
QSize profileSize() const;
QRect effectRect() const;
QVariantList effectPolygon() const;
+ QVariantList effectRoto() const;
void setEffectKeyframe(bool enable);
void sendFrameForAnalysis(bool analyse);
void updateAudioForAnalysis();
diff --git a/src/monitor/qmlmanager.cpp b/src/monitor/qmlmanager.cpp
index b76c3a7..782a591 100644
--- a/src/monitor/qmlmanager.cpp
+++ b/src/monitor/qmlmanager.cpp
@@ -88,7 +88,7 @@ void QmlManager::setScene(Kdenlive::MonitorId id, MonitorSceneType type, QSize p
//TODO
m_view->setSource(QUrl(QStringLiteral("qrc:/qml/kdenlivemonitorrotoscene.qml")));
root = m_view->rootObject();
- QObject::connect(root, SIGNAL(effectPolygonChanged()), this, SLOT(effectPolygonChanged()), Qt::UniqueConnection);
+ QObject::connect(root, SIGNAL(effectPolygonChanged()), this, SLOT(effectRotoChanged()), Qt::UniqueConnection);
root->setProperty("profile", QPoint(profile.width(), profile.height()));
root->setProperty("framesize", QRect(0, 0, profile.width(), profile.height()));
root->setProperty("scalex", (double) displayRect.width() / profile.width() * zoom);
@@ -129,3 +129,18 @@ void QmlManager::effectPolygonChanged()
QVariantList points = m_view->rootObject()->property("centerPoints").toList();
emit effectPointsChanged(points);
}
+
+void QmlManager::effectRotoChanged()
+{
+ if (!m_view->rootObject()) return;
+ QVariantList points = m_view->rootObject()->property("centerPoints").toList();
+ QVariantList controlPoints = m_view->rootObject()->property("centerPointsTypes").toList();
+ // rotoscoping effect needs a list of
+ QVariantList mix;
+ for (int i = 0; i < points.count(); i++) {
+ mix << controlPoints.at(2 * i);
+ mix << points.at(i);
+ mix << controlPoints.at(2 * i + 1);
+ }
+ emit effectPointsChanged(mix);
+}
diff --git a/src/monitor/qmlmanager.h b/src/monitor/qmlmanager.h
index 220f3a2..fa819f3 100644
--- a/src/monitor/qmlmanager.h
+++ b/src/monitor/qmlmanager.h
@@ -55,6 +55,7 @@ private:
private slots:
void effectRectChanged();
void effectPolygonChanged();
+ void effectRotoChanged();
signals:
void effectChanged(const QRect);
diff --git a/src/onmonitoritems/rotoscoping/rotowidget.cpp b/src/onmonitoritems/rotoscoping/rotowidget.cpp
index 6406bd1..c8ddc20 100644
--- a/src/onmonitoritems/rotoscoping/rotowidget.cpp
+++ b/src/onmonitoritems/rotoscoping/rotowidget.cpp
@@ -53,25 +53,23 @@ RotoWidget::RotoWidget(const QByteArray &data, Monitor *monitor, const ItemInfo
QVBoxLayout *l = new QVBoxLayout(this);
m_keyframeWidget = new SimpleKeyframeWidget(t, m_out - m_in, this);
l->addWidget(m_keyframeWidget);
-
+ connect(m_monitor, SIGNAL(effectPointsChanged(QVariantList)), this, SLOT(slotUpdateDataPoints(QVariantList)));
//MonitorEditWidget *edit = NULL; //monitor->getEffectEdit();
//m_scene = NULL;//edit->getScene();
//m_scene->cleanup();
// TODO: port to qml monitor scene
/*m_item = new SplineItem(QList <BPoint>(), NULL, m_scene);
-
connect(m_item, SIGNAL(changed(bool)), this, SLOT(slotUpdateData(bool)));
+ connect(m_scene, SIGNAL(addKeyframe()), this, SLOT(slotAddKeyframe()));
+ */
connect(m_keyframeWidget, SIGNAL(positionChanged(int)), this, SLOT(slotPositionChanged(int)));
connect(m_keyframeWidget, SIGNAL(keyframeAdded(int)), this, SLOT(slotAddKeyframe(int)));
connect(m_keyframeWidget, SIGNAL(keyframeRemoved(int)), this, SLOT(slotRemoveKeyframe(int)));
connect(m_keyframeWidget, SIGNAL(keyframeMoved(int,int)), this, SLOT(slotMoveKeyframe(int,int)));
- connect(m_scene, SIGNAL(addKeyframe()), this, SLOT(slotAddKeyframe()));
setSpline(data, false);
setupTrackingListen(info);
- m_scene->centerView();
- */
}
RotoWidget::~RotoWidget()
@@ -93,18 +91,14 @@ void RotoWidget::slotSyncPosition(int relTimelinePos)
slotPositionChanged(relTimelinePos, false);
}
-void RotoWidget::slotUpdateData(int pos, bool editing)
+void RotoWidget::slotUpdateData(int pos, QList <BPoint> spline)
{
- Q_UNUSED(editing)
-
int width = m_monitor->render->frameRenderWidth();
int height = m_monitor->render->renderHeight();
/*
* use the position of the on-monitor points to create a storable list
*/
- //TODO: get points from monitor qml scene
- QList <BPoint> spline; // = m_item->getPoints();
QList <QVariant> vlist;
foreach (const BPoint &point, spline) {
QList <QVariant> pl;
@@ -131,9 +125,14 @@ void RotoWidget::slotUpdateData(int pos, bool editing)
emit valueChanged();
}
-void RotoWidget::slotUpdateData(bool editing)
+void RotoWidget::slotUpdateDataPoints(QVariantList points, int pos)
{
- slotUpdateData(-1, editing);
+ QList <BPoint> bPoints;
+ for (int i = 0; i < points.size() / 3; i++) {
+ BPoint b(points.at(3 * i).toPointF(), points.at(3 * i + 1).toPointF(), points.at(3 * i + 2).toPointF());
+ bPoints << b;
+ }
+ slotUpdateData(pos, bPoints);
}
QByteArray RotoWidget::getSpline()
@@ -154,6 +153,7 @@ void RotoWidget::slotPositionChanged(int pos, bool seek)
pos += m_in;
QList <BPoint> p;
+ bool isKeyframe = false;
if (m_data.canConvert(QVariant::Map)) {
QMap <QString, QVariant> map = m_data.toMap();
@@ -187,13 +187,9 @@ void RotoWidget::slotPositionChanged(int pos, bool seek)
}
p.append(bp);
}
-
- // TODO: port to qml monitor scene
- /*m_item->setPoints(p);
- m_item->setEnabled(false);*/
- //m_scene->setEnabled(false);
} else {
p = getPoints(keyframe2);
+ isKeyframe = pos == keyframe2;
// only update if necessary to preserve the current point selection
// TODO: port to qml monitor scene
/*
@@ -204,6 +200,7 @@ void RotoWidget::slotPositionChanged(int pos, bool seek)
}
} else {
p = getPoints(-1);
+ isKeyframe = true;
// only update if necessary to preserve the current point selection
// TODO: port to qml monitor scene
/*if (p != m_item->getPoints())
@@ -211,6 +208,15 @@ void RotoWidget::slotPositionChanged(int pos, bool seek)
m_item->setEnabled(true);*/
//m_scene->setEnabled(true);
}
+ QVariantList centerPoints;
+ QVariantList controlPoints;
+ for (int i = 0; i < p.size(); i++) {
+ centerPoints << QVariant(p.at(i).p);
+ controlPoints << QVariant(p.at(i).h1);
+ controlPoints << QVariant(p.at(i).h2);
+ }
+ m_monitor->setUpEffectGeometry(QRect(), centerPoints, controlPoints);
+ m_monitor->setEffectKeyframe(isKeyframe);
if (seek)
emit seekToPos(pos - m_in);
@@ -252,11 +258,7 @@ void RotoWidget::slotAddKeyframe(int pos)
if (pos < 0)
m_keyframeWidget->addKeyframe();
-
- slotUpdateData(pos);
- // TODO: port to qml monitor scene
- //m_item->setEnabled(true);
- //m_scene->setEnabled(true);
+ slotUpdateDataPoints(m_monitor->effectRoto(), pos);
}
void RotoWidget::slotRemoveKeyframe(int pos)
diff --git a/src/onmonitoritems/rotoscoping/rotowidget.h b/src/onmonitoritems/rotoscoping/rotowidget.h
index 5cc0d23..3b60671 100644
--- a/src/onmonitoritems/rotoscoping/rotowidget.h
+++ b/src/onmonitoritems/rotoscoping/rotowidget.h
@@ -87,9 +87,9 @@ private:
private slots:
/** @brief Updates/Creates the spline at @param pos based on the on-monitor items. */
- void slotUpdateData(int pos = -1, bool editing = false);
+ void slotUpdateData(int pos, QList <BPoint> spline);
/** @brief Updates/Creates the spline at the current timeline position based on the on-monitor items. */
- void slotUpdateData(bool editing);
+ void slotUpdateDataPoints(QVariantList points, int pos = -1);
/** @brief Updates the on-monitor items to fit the spline at position @param pos. */
void slotPositionChanged(int pos, bool seek = true);