Commit bbc9a66e authored by Till Theato's avatar Till Theato

First work on rotoscoping GUI

(MLT module: github.com/ttill/MLT-roto)

svn path=/trunk/kdenlive/; revision=5367
parent 1f9a8887
......@@ -77,6 +77,7 @@ grain
lines
oldfilm
tcolor
rotoscoping
#effects that have simplekeyframes
vignette
......@@ -115,5 +115,6 @@ vignette.xml
swapchannels.xml
audiobalance.xml
audiopan.xml
rotoscoping.xml
DESTINATION ${DATA_INSTALL_DIR}/kdenlive/effects)
<!DOCTYPE kpartgui>
<effect tag="rotoscoping" id="rotoscoping">
<name>Rotoscoping</name>
<description>Keyframable vector based rotoscoping</description>
<author>Till Theato</author>
<parameter type="list" name="mode" default="alpha" paramlist="alpha,matte,rgb">
<paramlistdisplay>Alpha,Matte,RGB</paramlistdisplay>
<name>Mode</name>
</parameter>
<parameter type="list" name="alpha_operation" default="clear" paramlist="clear,max,min,add,sub">
<paramlistdisplay>Write on clear,Maximum,Minimum,Add,Subtract</paramlistdisplay>
<name>Alpha Operation</name>
</parameter>
<parameter type="bool" name="invert" default="0">
<name>Invert</name>
</parameter>
<parameter type="constant" name="precision" max="500" min="1" default="1">
<name>Precision</name>
</parameter>
<parameter type="roto-spline" name="spline" default="[[[0,1],[0,0],[1,0]],[[1,0],[1,1],[0,1]]]"> <!-- TODO: set default to "" -->
<name>Rotoscopy Spline</name>
</parameter>
</effect>
......@@ -3,17 +3,21 @@ add_subdirectory(colorcorrection)
add_subdirectory(kiss_fft)
add_subdirectory(mimetypes)
add_subdirectory(onmonitoritems)
add_subdirectory(rotoscoping)
add_subdirectory(widgets)
macro_optional_find_package(Nepomuk)
include(FindQImageBlitz)
find_package(QJSON)
include_directories(
${KDE4_INCLUDE_DIR}
${KDE4_INCLUDE_DIR}/KDE
${QT_INCLUDES}
${LIBMLT_INCLUDE_DIR}
${LIBMLTPLUS_INCLUDE_DIR}
${QJSON_INCLUDE_DIR}
${QDBUS_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
......@@ -22,6 +26,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/colorcorrection
${CMAKE_SOURCE_DIR}/src/kiss_fft
${CMAKE_SOURCE_DIR}/src/onmonitoritems
${CMAKE_SOURCE_DIR}/src/onmonitoritems/rotoscoping
${CMAKE_SOURCE_DIR}/src/widgets
)
......@@ -256,6 +261,8 @@ set(kdenlive_SRCS
blackmagic/devices.cpp
onmonitoritems/onmonitorrectitem.cpp
onmonitoritems/onmonitorcornersitem.cpp
onmonitoritems/rotoscoping/splineitem.cpp
onmonitoritems/rotoscoping/bpointitem.cpp
cornerswidget.cpp
kiss_fft/_kiss_fft_guts.h
kiss_fft/kiss_fft.c
......@@ -266,6 +273,7 @@ set(kdenlive_SRCS
beziercurve/cubicbezierspline.cpp
dragvalue.cpp
monitoreditwidget.cpp
rotoscoping/rotowidget.cpp
)
add_definitions(${KDE4_DEFINITIONS})
......@@ -321,6 +329,7 @@ target_link_libraries(kdenlive
${KDE4_KROSSUI_LIBS}
${CMAKE_DL_LIBS}
${CMAKE_THREAD_LIBS_INIT}
${QJSON_LIBRARIES}
)
if(Q_WS_X11)
......
......@@ -35,6 +35,7 @@
#include "doubleparameterwidget.h"
#include "cornerswidget.h"
#include "beziercurve/beziersplinewidget.h"
#include "rotoscoping/rotowidget.h"
#include <KDebug>
#include <KLocale>
......@@ -407,6 +408,15 @@ void EffectStackEdit::transferParamDesc(const QDomElement d, int pos, int in, in
QString depends = pa.attribute("depends");
if (!depends.isEmpty())
meetDependency(paramName, type, EffectsList::parameter(e, depends));
} else if (type == "roto-spline") {
RotoWidget *roto = new RotoWidget(value, m_monitor, m_in, m_out, this);
roto->slotShowScene(!disable);
connect(roto, SIGNAL(valueChanged()), this, SLOT(collectAllParameters()));
connect(roto, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
connect(this, SIGNAL(syncEffectsPos(int)), roto, SLOT(slotSyncPosition(int)));
connect(this, SIGNAL(effectStateChanged(bool)), roto, SLOT(slotShowScene(bool)));
m_vbox->addWidget(roto);
m_valueItems[paramName] = roto;
} else if (type == "wipe") {
Wipeval *wpval = new Wipeval;
wpval->setupUi(toFillin);
......@@ -672,6 +682,9 @@ void EffectStackEdit::collectAllParameters()
QString depends = pa.attributes().namedItem("depends").nodeValue();
if (!depends.isEmpty())
meetDependency(paramName, type, EffectsList::parameter(newparam, depends));
} else if (type == "roto-spline") {
RotoWidget *widget = static_cast<RotoWidget *>(m_valueItems.value(paramName));
setValue = widget->getSpline();
} else if (type == "wipe") {
Wipeval *wp = (Wipeval*)m_valueItems.value(paramName);
wipeInfo info;
......
# Empty cmake file to satisfy CMake
\ No newline at end of file
add_subdirectory(rotoscoping)
/***************************************************************************
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
* This file is part of Kdenlive (www.kdenlive.org). *
* *
* Kdenlive 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 2 of the License, or *
* (at your option) any later version. *
* *
* Kdenlive 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 Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#include "bpointitem.h"
#include "splineitem.h"
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include <QCursor>
BPointItem::BPointItem(BPoint point, QGraphicsItem* parent) :
QAbstractGraphicsShapeItem(parent),
m_selection(-1)
{
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
QPen framepen(Qt::SolidLine);
framepen.setColor(Qt::yellow);
setPen(framepen);
setBrush(Qt::NoBrush);
setAcceptHoverEvents(true);
setPos(point.p);
m_point.h1 = mapFromScene(point.h1);
m_point.p = mapFromScene(point.p);
m_point.h2 = mapFromScene(point.h2);
m_point.handlesLinked = false;
}
BPoint BPointItem::getPoint()
{
return BPoint(mapToScene(m_point.h1), mapToScene(m_point.p), mapToScene(m_point.h2));
}
int BPointItem::type() const
{
return Type;
}
QRectF BPointItem::boundingRect() const
{
QPolygonF p = QPolygonF() << m_point.h1 << m_point.p << m_point.h2;
return p.boundingRect().adjusted(-6, -6, 6, 6);
}
void BPointItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setPen(QPen(Qt::yellow, 1, Qt::SolidLine));
painter->setBrush(QBrush(isSelected() ? Qt::red : Qt::yellow));
painter->setRenderHint(QPainter::Antialiasing);
double handleSize = 6 / painter->matrix().m11();
double handleSizeHalf = handleSize / 2;
QPolygonF handle = QPolygonF() << QPointF(0, -handleSizeHalf) << QPointF(handleSizeHalf, 0) << QPointF(0, handleSizeHalf) << QPointF(-handleSizeHalf, 0);
painter->drawLine(m_point.h1, m_point.p);
painter->drawLine(m_point.p, m_point.h2);
#if QT_VERSION >= 0x040600
painter->drawConvexPolygon(handle.translated(m_point.h1.x(), m_point.h1.y()));
painter->drawConvexPolygon(handle.translated(m_point.h2.x(), m_point.h2.y()));
#else
tmp = handle;
tmp.translate(m_point.h1.x(), m_point.h1.y());
p.drawConvexPolygon(tmp);
tmp.translate(m_point.h2.x(), m_point.h2.y());
p.drawConvexPolygon(tmp);
#endif
painter->drawEllipse(QRectF(m_point.p.x() - handleSizeHalf,
m_point.p.y() - handleSizeHalf, handleSize, handleSize));
}
int BPointItem::getSelection(QPointF pos)
{
QPainterPath mouseArea;
mouseArea.addRect(pos.x() - 6, pos.y() - 6, 12, 12);
if (mouseArea.contains(m_point.p))
return 1;
else if (mouseArea.contains(m_point.h1))
return 0;
else if (mouseArea.contains(m_point.h2))
return 2;
return -1;
}
void BPointItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
m_selection = getSelection(event->pos());
if (m_selection < 0) {
event->ignore();
setSelected(false);
} else {
setSelected(true);
}
}
void BPointItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
{
prepareGeometryChange();
switch (m_selection) {
case 0:
m_point.setH1(event->pos());
break;
case 1:
m_point.setP(event->pos());
break;
case 2:
m_point.setH2(event->pos());
break;
}
if (parentItem()) {
SplineItem *parent = qgraphicsitem_cast<SplineItem*>(parentItem());
if (parent)
parent->updateSpline();
}
}
void BPointItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
QGraphicsItem::mouseReleaseEvent(event);
}
void BPointItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
{
if (getSelection(event->pos()) < 0)
unsetCursor();
else
setCursor(QCursor(Qt::PointingHandCursor));
}
/***************************************************************************
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
* This file is part of Kdenlive (www.kdenlive.org). *
* *
* Kdenlive 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 2 of the License, or *
* (at your option) any later version. *
* *
* Kdenlive 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 Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef BPOINTITEM_H
#define BPOINTITEM_H
#include "bpoint.h"
#include <QtCore>
#include <QAbstractGraphicsShapeItem>
class BPointItem : public QAbstractGraphicsShapeItem
{
public:
BPointItem(BPoint point, QGraphicsItem* parent = 0);
BPoint getPoint();
enum { Type = UserType + 11 };
virtual int type() const;
virtual QRectF boundingRect() const;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
protected:
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
private:
BPoint m_point;
int m_selection;
/** @brief Gets The action mode for the area @param pos +- 4. */
int getSelection(QPointF pos);
};
#endif
/***************************************************************************
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
* This file is part of Kdenlive (www.kdenlive.org). *
* *
* Kdenlive 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 2 of the License, or *
* (at your option) any later version. *
* *
* Kdenlive 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 Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#include "splineitem.h"
#include "bpointitem.h"
#include <QGraphicsScene>
SplineItem::SplineItem(const QList< BPoint >& points, QGraphicsItem* parent, QGraphicsScene *scene) :
QGraphicsPathItem(parent, scene)
{
QPen framepen(Qt::SolidLine);
framepen.setColor(Qt::yellow);
setPen(framepen);
setBrush(Qt::NoBrush);
if (points.isEmpty())
return;
QPainterPath path(points.at(0).p);
int j;
for (int i = 0; i < points.count(); ++i) {
new BPointItem(points.at(i), this);
j = (i + 1) % points.count();
path.cubicTo(points.at(i).h2, points.at(j).h1, points.at(j).p);
}
setPath(path);
}
int SplineItem::type() const
{
return Type;
}
void SplineItem::updateSpline()
{
QPainterPath path(qgraphicsitem_cast<BPointItem *>(childItems().at(0))->getPoint().p);
BPoint p1, p2;
int j;
for (int i = 0; i < childItems().count(); ++i) {
j = (i + 1) % childItems().count();
p1 = qgraphicsitem_cast<BPointItem *>(childItems().at(i))->getPoint();
p2 = qgraphicsitem_cast<BPointItem *>(childItems().at(j))->getPoint();
path.cubicTo(p1.h2, p2.h1, p2.p);
}
setPath(path);
emit changed();
}
QList <BPoint> SplineItem::getPoints()
{
QList <BPoint> points;
foreach (QGraphicsItem *child, childItems())
points << qgraphicsitem_cast<BPointItem *>(child)->getPoint();
return points;
}
#include "splineitem.moc"
/***************************************************************************
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
* This file is part of Kdenlive (www.kdenlive.org). *
* *
* Kdenlive 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 2 of the License, or *
* (at your option) any later version. *
* *
* Kdenlive 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 Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef SPLINEITEM_H
#define SPLINEITEM_H
#include <QtCore>
#include <QGraphicsPathItem>
class BPoint;
class SplineItem : public QObject, public QGraphicsPathItem
{
Q_OBJECT
public:
SplineItem(const QList <BPoint> &points, QGraphicsItem* parent = 0, QGraphicsScene *scene = 0);
enum { Type = UserType + 10 };
virtual int type() const;
void updateSpline();
QList <BPoint> getPoints();
signals:
void changed();
};
#endif
/***************************************************************************
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
* This file is part of Kdenlive (www.kdenlive.org). *
* *
* Kdenlive 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 2 of the License, or *
* (at your option) any later version. *
* *
* Kdenlive 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 Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#include "rotowidget.h"
#include "monitor.h"
#include "renderer.h"
#include "monitorscene.h"
#include "monitoreditwidget.h"
#include "onmonitoritems/rotoscoping/bpointitem.h"
#include "onmonitoritems/rotoscoping/splineitem.h"
#include <qjson/parser.h>
#include <qjson/serializer.h>
RotoWidget::RotoWidget(QString data, Monitor *monitor, int in, int out, QWidget* parent) :
QWidget(parent),
m_monitor(monitor),
m_showScene(true),
m_in(in),
m_out(out),
m_pos(0)
{
MonitorEditWidget *edit = monitor->getEffectEdit();
edit->showVisibilityButton(true);
m_scene = edit->getScene();
QJson::Parser parser;
bool ok;
m_data = parser.parse(data.toUtf8(), &ok);
if (!ok) {
// :(
}
int width = m_monitor->render->frameRenderWidth();
int height = m_monitor->render->renderHeight();
QList <BPoint> points;
foreach (const QVariant &bpoint, m_data.toList()) {
QList <QVariant> l = bpoint.toList();
BPoint p;
p.h1 = QPointF(l.at(0).toList().at(0).toDouble() * width, l.at(0).toList().at(1).toDouble() * height);
p.p = QPointF(l.at(1).toList().at(0).toDouble() * width, l.at(2).toList().at(1).toDouble() * height);
p.h2 = QPointF(l.at(2).toList().at(0).toDouble() * width, l.at(2).toList().at(1).toDouble() * height);
points << p;
}
m_item = new SplineItem(points, NULL, m_scene);
connect(m_item, SIGNAL(changed()), this, SLOT(slotUpdateData()));
connect(edit, SIGNAL(showEdit(bool)), this, SLOT(slotShowScene(bool)));
connect(m_monitor, SIGNAL(renderPosition(int)), this, SLOT(slotCheckMonitorPosition(int)));
}
RotoWidget::~RotoWidget()
{
m_scene->removeItem(m_item);
delete m_item;
if (m_monitor) {
MonitorEditWidget *edit = m_monitor->getEffectEdit();
edit->showVisibilityButton(false);
edit->removeCustomControls();
m_monitor->slotEffectScene(false);
}
}
void RotoWidget::slotCheckMonitorPosition(int renderPos)
{
if (m_showScene)
emit checkMonitorPosition(renderPos);
}
void RotoWidget::slotSyncPosition(int relTimelinePos)
{
Q_UNUSED(relTimelinePos);
}
void RotoWidget::slotShowScene(bool show)
{
m_showScene = show;
if (!m_showScene)
m_monitor->slotEffectScene(false);
else
slotCheckMonitorPosition(m_monitor->render->seekFramePosition());
}
void RotoWidget::slotUpdateData()
{
int width = m_monitor->render->frameRenderWidth();
int height = m_monitor->render->renderHeight();
QList <BPoint> spline = m_item->getPoints();
QList <QVariant> vlist;
foreach (const BPoint &point, spline) {
QList <QVariant> pl;
for (int i = 0; i < 3; ++i)
pl << QVariant(QList <QVariant>() << QVariant(point[i].x() / width) << QVariant(point[i].y() / height));
vlist << QVariant(pl);
}
m_data = QVariant(vlist);
emit valueChanged();
}
QString RotoWidget::getSpline()
{
QJson::Serializer serializer;
return QString(serializer.serialize(m_data));
}
#include "rotowidget.moc"
/***************************************************************************
* Copyright (C) 2011 by Till Theato (root@ttill.de) *
* This file is part of Kdenlive (www.kdenlive.org). *
* *
* Kdenlive 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 2 of the License, or *
* (at your option) any later version. *
* *
* Kdenlive 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 Kdenlive. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifndef ROTOWIDGET_H
#define ROTOWIDGET_H
#include "bpoint.h"
#include <QWidget>
class Monitor;
class MonitorScene;
class SplineItem;
class RotoWidget : public QWidget
{
Q_OBJECT
public:
RotoWidget(QString data, Monitor *monitor, int in, int out, QWidget* parent = 0);
virtual ~RotoWidget();
QString getSpline();
public slots:
/** @brief Switches from normal monitor to monitor scene according to @param show. */
void slotShowScene(bool show = true);
/** @brief Updates the on-monitor item. */
void slotSyncPosition(int relTimelinePos);
signals:
void valueChanged();
void checkMonitorPosition(int);
private:
Monitor *m_monitor;
MonitorScene *m_scene;
bool m_showScene;
QVariant m_data;
SplineItem *m_item;
int m_in;
int m_out;
int m_pos;
private slots:
/** @brief Makes sure the monitor effect scene is only visible if the clip this geometry belongs to is visible.
* @param renderPos Postion of the Monitor / Timeline cursor */
void slotCheckMonitorPosition(int renderPos);
void slotUpdateData();
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment