<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<data name="effects" version="0">
- <group list="brightness,gamma,frei0r.balanc0r,frei0r.brightness,frei0r.levels,frei0r.three_point_balance,frei0r.curves,frei0r.coloradj_RGB,frei0r.sopsat">
+ <group list="brightness,gamma,frei0r.balanc0r,frei0r.brightness,frei0r.levels,frei0r.three_point_balance,frei0r.curves,frei0r.coloradj_RGB,frei0r.sopsat,frei0r.bezier_curves">
<text>Colour correction</text>
</group>
<group list="invert,sepia,tcolor,greyscale,frei0r.B,frei0r.G,frei0r.R,frei0r.contrast0r,frei0r.saturat0r,frei0r.tint0r,frei0r.primaries,frei0r.rgbparade,chroma_hold,frei0r.hueshift0r">
frei0r_alphagrad.xml
frei0r_alphaspot.xml
frei0r_balanc0r.xml
+frei0r_bezier_curves.xml
frei0r_brightness.xml
frei0r_coloradj_rgb.xml
frei0r_colordistance.xml
--- /dev/null
+<!DOCTYPE kpartgui>
+<effect tag="frei0r.curves" id="frei0r.bezier_curves">
+ <name>Bézier Curves</name>
+ <description>Color curves adjustment</description>
+ <author>Maksim Golovkin, Till Theato</author>
+
+ <parameter type="list" name="Channel" default="0" paramlist="0,1,2,3" paramlistdisplay="Red,Green,Blue,Luma">
+ <name>Channel</name>
+ </parameter>
+
+ <parameter type="list" name="Luma formula" default="1" paramlist="0,1" paramlistdisplay="Rec. 601,Rec. 709">
+ <name>Luma formula</name>
+ </parameter>
+
+ <parameter type="bezier_spline" name="Bézier spline" depends="Channel" default="0;0#0;0#0;0.5|1;0.5#1;1#1;1">
+ <name>Bézier Curve(Spline) Widget</name>
+ </parameter>
+</effect>
-add_subdirectory(widgets)
-add_subdirectory(mimetypes)
+add_subdirectory(beziercurve)
+add_subdirectory(colorcorrection)
add_subdirectory(kiss_fft)
+add_subdirectory(mimetypes)
+add_subdirectory(onmonitoritems)
+add_subdirectory(widgets)
macro_optional_find_package(Nepomuk)
include(FindQImageBlitz)
${QDBUS_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
- ${CMAKE_SOURCE_DIR}/src/widgets
+ ${CMAKE_SOURCE_DIR}/src/audioscopes
+ ${CMAKE_SOURCE_DIR}/src/beziercurve
${CMAKE_SOURCE_DIR}/src/colorcorrection
- ${CMAKE_SOURCE_DIR}/src/onmonitoritems
${CMAKE_SOURCE_DIR}/src/kiss_fft
- ${CMAKE_SOURCE_DIR}/src/audioscopes
+ ${CMAKE_SOURCE_DIR}/src/onmonitoritems
+ ${CMAKE_SOURCE_DIR}/src/widgets
)
kiss_fft/_kiss_fft_guts.h
kiss_fft/kiss_fft.c
kiss_fft/tools/kiss_fftr.c
+ beziercurve/cubicbezierspline.cpp
+ beziercurve/beziersplinewidget.cpp
)
-add_subdirectory(${CMAKE_SOURCE_DIR}/src/colorcorrection)
-add_subdirectory(${CMAKE_SOURCE_DIR}/src/onmonitoritems)
-
add_definitions(${KDE4_DEFINITIONS})
if(APPLE OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR NO_JOGSHUTTLE)
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2010 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 "beziersplinewidget.h"
+
+#include <QPainter>
+#include <QMouseEvent>
+
+#include <KDebug>
+
+BezierSplineWidget::BezierSplineWidget(QWidget* parent) :
+ QWidget(parent),
+ m_mode(ModeNormal),
+ m_currentPointIndex(-1)
+{
+ //m_spline.setPrecision(width());
+ setMouseTracking(true);
+ setAutoFillBackground(false);
+ setAttribute(Qt::WA_OpaquePaintEvent);
+ setMinimumSize(150, 150);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+}
+
+CubicBezierSpline BezierSplineWidget::spline()
+{
+ return m_spline;
+}
+
+void BezierSplineWidget::setSpline(const CubicBezierSpline& spline)
+{
+ // TODO: cleanup
+ m_spline.fromString(spline.toString());
+}
+
+void BezierSplineWidget::paintEvent(QPaintEvent* event)
+{
+ Q_UNUSED(event);
+
+ QPainter p(this);
+
+ p.fillRect(rect(), palette().background());
+
+ int wWidth = width() - 1;
+ int wHeight = height() - 1;
+
+ // Draw curve.
+ double prevY = wHeight - m_spline.value(0.) * wHeight;
+ double prevX = 0.;
+ double curY;
+ double normalizedX = -1;
+ int x;
+
+ p.setPen(QPen(Qt::black, 1, Qt::SolidLine));
+ for (x = 0 ; x < wWidth ; ++x) {
+ normalizedX = x / (double)wWidth;
+ curY = wHeight - m_spline.value(normalizedX, true) * wHeight;
+
+ /**
+ * Keep in mind that QLineF rounds doubles
+ * to ints mathematically, not just rounds down
+ * like in C
+ */
+ p.drawLine(QLineF(prevX, prevY,
+ x, curY));
+ prevX = x;
+ prevY = curY;
+ }
+ p.drawLine(QLineF(prevX, prevY ,
+ x, wHeight - m_spline.value(1.0, true) * wHeight));
+
+ // Drawing curve handles.
+ p.setPen(QPen(Qt::red, 1, Qt::SolidLine));
+ BPoint point;
+ for (int i = 0; i < m_spline.points().count(); ++i) {
+ point = m_spline.points().at(i);
+ p.drawEllipse(QRectF(point.h1.x() * wWidth - 3,
+ wHeight - 3 - point.h1.y() * wHeight, 6, 6));
+ p.drawEllipse(QRectF(point.p.x() * wWidth - 3,
+ wHeight - 3 - point.p.y() * wHeight, 6, 6));
+ p.drawEllipse(QRectF(point.h2.x() * wWidth - 3,
+ wHeight - 3 - point.h2.y() * wHeight, 6, 6));
+ }
+}
+
+void BezierSplineWidget::resizeEvent(QResizeEvent* event)
+{
+ m_spline.setPrecision(width());
+ QWidget::resizeEvent(event);
+}
+
+void BezierSplineWidget::mousePressEvent(QMouseEvent* event)
+{
+ double x = event->pos().x() / (double)(width() - 1);
+ double y = 1.0 - event->pos().y() / (double)(height() - 1);
+
+ point_types selectedPoint;
+ int closest_point_index = nearestPointInRange(QPointF(x, y), width(), height(), &selectedPoint);
+
+ /*if (event->button() == Qt::RightButton && closest_point_index > 0 && closest_point_index < d->m_curve.points().count() - 1) {
+ d->m_curve.removePoint(closest_point_index);
+ setCursor(Qt::ArrowCursor);
+ d->setState(ST_NORMAL);
+ if (closest_point_index < d->m_grab_point_index)
+ --d->m_grab_point_index;
+ d->setCurveModified();
+ return;
+ } else*/ if (event->button() != Qt::LeftButton) return;
+
+ if (closest_point_index < 0) {
+ BPoint po;
+ po.p = QPointF(x, y);
+ po.h1 = QPointF(x-0.05, y-0.05);
+ po.h2 = QPointF(x+0.05, y+0.05);
+ m_currentPointIndex = m_spline.addPoint(po);
+ m_currentPointType = PTypeP;
+ if (m_currentPointIndex == -1) // x already in use
+ return;
+ /*if (!d->jumpOverExistingPoints(newPoint, -1)) return;*/
+ } else {
+ m_currentPointIndex = closest_point_index;
+ m_currentPointType = selectedPoint;
+ }
+
+ BPoint point = m_spline.points()[m_currentPointIndex];
+ QPointF p;
+ switch (m_currentPointType) {
+ case PTypeH1:
+ p = point.h1;
+ break;
+ case PTypeP:
+ p = point.p;
+ break;
+ case PTypeH2:
+ p = point.h2;
+ }
+
+ m_grabOriginalX = p.x();
+ m_grabOriginalY = p.y();
+ m_grabOffsetX = p.x() - x;
+ m_grabOffsetY = p.y() - y;
+
+ switch (m_currentPointType) {
+ case PTypeH1:
+ point.h1 = QPointF(x + m_grabOffsetX, y + m_grabOffsetY);
+ break;
+ case PTypeP:
+ point.p = QPointF(x + m_grabOffsetX, y + m_grabOffsetY);
+ break;
+ case PTypeH2:
+ point.h2 = QPointF(x + m_grabOffsetX, y + m_grabOffsetY);
+ }
+ m_spline.setPoint(m_currentPointIndex, point);
+
+ //d->m_draggedAwayPointIndex = -1;
+
+ m_mode = ModeDrag;
+
+ update();
+}
+
+void BezierSplineWidget::mouseReleaseEvent(QMouseEvent* event)
+{
+ if (event->button() != Qt::LeftButton)
+ return;
+
+ setCursor(Qt::ArrowCursor);
+ m_mode = ModeNormal;
+
+ emit modified();
+}
+
+void BezierSplineWidget::mouseMoveEvent(QMouseEvent* event)
+{
+ double x = event->pos().x() / (double)(width() - 1);
+ double y = 1.0 - event->pos().y() / (double)(height() - 1);
+
+ if (m_mode == ModeNormal) { // If no point is selected set the the cursor shape if on top
+ point_types type;
+ int nearestPointIndex = nearestPointInRange(QPointF(x, y), width(), height(), &type);
+
+ if (nearestPointIndex < 0)
+ setCursor(Qt::ArrowCursor);
+ else
+ setCursor(Qt::CrossCursor);
+ } else { // Else, drag the selected point
+ /*bool crossedHoriz = event->pos().x() - width() > MOUSE_AWAY_THRES ||
+ event->pos().x() < -MOUSE_AWAY_THRES;
+ bool crossedVert = event->pos().y() - height() > MOUSE_AWAY_THRES ||
+ event->pos().y() < -MOUSE_AWAY_THRES;
+
+ bool removePoint = (crossedHoriz || crossedVert);
+
+ if (!removePoint && d->m_draggedAwayPointIndex >= 0) {
+ // point is no longer dragged away so reinsert it
+ QPointF newPoint(d->m_draggedAwayPoint);
+ d->m_grab_point_index = d->m_curve.addPoint(newPoint);
+ d->m_draggedAwayPointIndex = -1;
+ }
+
+ if (removePoint &&
+ (d->m_draggedAwayPointIndex >= 0))
+ return;
+ */
+
+ setCursor(Qt::CrossCursor);
+
+ x += m_grabOffsetX;
+ y += m_grabOffsetY;
+
+ double leftX, rightX;
+ BPoint point = m_spline.points()[m_currentPointIndex];
+ switch (m_currentPointType) {
+ case PTypeH1:
+ rightX = point.p.x();
+ if (m_currentPointIndex == 0)
+ leftX = -1000;
+ else
+ leftX = m_spline.points()[m_currentPointIndex - 1].p.x();
+ x = qBound(leftX, x, rightX);
+ point.h1 = QPointF(x, y);
+ break;
+ case PTypeP:
+ if (m_currentPointIndex == 0) {
+ leftX = 0.0;
+ rightX = 0.0;
+ /*if (d->m_curve.points().count() > 1)
+ * rightX = d->m_curve.points()[d->m_grab_point_index + 1].x() - POINT_AREA;
+ * else
+ * rightX = 1.0;*/
+ } else if (m_currentPointIndex == m_spline.points().count() - 1) {
+ leftX = 1.0;//m_spline.points()[m_currentPointIndex - 1].p.x();
+ rightX = 1.0;
+ } else {
+ //// the 1E-4 addition so we can grab the dot later.
+ leftX = m_spline.points()[m_currentPointIndex - 1].p.x();// + POINT_AREA;
+ rightX = m_spline.points()[m_currentPointIndex + 1].p.x();// - POINT_AREA;
+ }
+ x = qBound(leftX, x, rightX);
+ y = qBound(0., y, 1.);
+ point.p = QPointF(x, y);
+ break;
+ case PTypeH2:
+ leftX = point.p.x();
+ if (m_currentPointIndex == m_spline.points().count() - 1)
+ rightX = 1001;
+ else
+ rightX = m_spline.points()[m_currentPointIndex + 1].p.x();
+ x = qBound(leftX, x, rightX);
+ point.h2 = QPointF(x, y);
+ };
+
+ m_spline.setPoint(m_currentPointIndex, point);
+
+ /*if (removePoint && d->m_curve.points().count() > 2) {
+ d->m_draggedAwayPoint = d->m_curve.points()[d->m_grab_point_index];
+ d->m_draggedAwayPointIndex = d->m_grab_point_index;
+ d->m_curve.removePoint(d->m_grab_point_index);
+ d->m_grab_point_index = bounds(d->m_grab_point_index, 0, d->m_curve.points().count() - 1);
+ }
+
+ d->setCurveModified();*/
+ update();
+ }
+}
+
+void BezierSplineWidget::leaveEvent(QEvent* event)
+{
+ QWidget::leaveEvent(event);
+}
+
+int BezierSplineWidget::nearestPointInRange(QPointF p, int wWidth, int wHeight, BezierSplineWidget::point_types* sel)
+{
+ double nearestDistanceSquared = 1000;
+ point_types selectedPoint;
+ int nearestIndex = -1;
+ int i = 0;
+
+ double distanceSquared;
+ foreach(const BPoint & point, m_spline.points()) {
+ distanceSquared = pow(point.h1.x() - p.x(), 2) + pow(point.h1.y() - p.y(), 2);
+ if (distanceSquared < nearestDistanceSquared) {
+ nearestIndex = i;
+ nearestDistanceSquared = distanceSquared;
+ selectedPoint = PTypeH1;
+ }
+ distanceSquared = pow(point.p.x() - p.x(), 2) + pow(point.p.y() - p.y(), 2);
+ if (distanceSquared < nearestDistanceSquared) {
+ nearestIndex = i;
+ nearestDistanceSquared = distanceSquared;
+ selectedPoint = PTypeP;
+ }
+ distanceSquared = pow(point.h2.x() - p.x(), 2) + pow(point.h2.y() - p.y(), 2);
+ if (distanceSquared < nearestDistanceSquared) {
+ nearestIndex = i;
+ nearestDistanceSquared = distanceSquared;
+ selectedPoint = PTypeH2;
+ }
+ ++i;
+ }
+
+ if (nearestIndex >= 0) {
+ BPoint point = m_spline.points()[nearestIndex];
+ QPointF p2;
+ switch (selectedPoint) {
+ case PTypeH1:
+ p2 = point.h1;
+ break;
+ case PTypeP:
+ p2 = point.p;
+ break;
+ case PTypeH2:
+ p2 = point.h2;
+ }
+ if (qAbs(p.x() - p2.x()) * (wWidth - 1) < 5 && qAbs(p.y() - p2.y()) * (wHeight - 1) < 5) {
+ *sel = selectedPoint;
+ return nearestIndex;
+ }
+ }
+
+ return -1;
+}
+
+#include "beziersplinewidget.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2010 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 BEZIERSPLINEWIDGET_H
+#define BEZIERSPLINEWIDGET_H
+
+#include "cubicbezierspline.h"
+
+#include <QtCore>
+#include <QWidget>
+
+class BezierSplineWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ BezierSplineWidget(QWidget* parent = 0);
+
+ CubicBezierSpline spline();
+ void setSpline(const CubicBezierSpline &spline);
+
+protected:
+ //void keyPressEvent(QKeyEvent *event);
+ void paintEvent(QPaintEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent * event);
+ void mouseMoveEvent(QMouseEvent * event);
+ void leaveEvent(QEvent *event);
+ void resizeEvent(QResizeEvent *event);
+
+private:
+ CubicBezierSpline m_spline;
+ enum modes { ModeDrag, ModeNormal };
+ enum point_types { PTypeH1, PTypeP, PTypeH2 };
+ modes m_mode;
+ int m_currentPointIndex;
+ point_types m_currentPointType;
+ double m_grabOffsetX;
+ double m_grabOffsetY;
+ double m_grabOriginalX;
+ double m_grabOriginalY;
+ //QPointF m_draggedAwayPoint;
+ //int m_draggedAwayPointIndex;
+
+ //inline void drawGrid(QPainter &p, int width, int height);
+ int nearestPointInRange(QPointF p, int wWidth, int wHeight, point_types *sel);
+
+signals:
+ void modified();
+};
+
+#endif
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2010 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 "cubicbezierspline.h"
+
+#include <KDebug>
+
+static bool pointLessThan(const BPoint &a, const BPoint &b)
+{
+ return a.p.x() < b.p.x();
+}
+
+CubicBezierSpline::CubicBezierSpline(QObject* parent) :
+ QObject(parent),
+ m_validSpline(false),
+ m_precision(100)
+{
+ BPoint start;
+ start.p.setX(0);
+ start.p.setY(0);
+ start.h1.setX(0);
+ start.h1.setY(0);
+ start.h2.setX(0.1);
+ start.h2.setY(0.1);
+ m_points.append(start);
+
+ BPoint end;
+ end.p.setX(1);
+ end.p.setY(1);
+ end.h1.setX(0.9);
+ end.h1.setY(0.9);
+ end.h2.setX(1);
+ end.h2.setY(1);
+ m_points.append(end);
+}
+
+CubicBezierSpline::CubicBezierSpline(const CubicBezierSpline& spline, QObject* parent) :
+ QObject(parent)
+{
+ m_precision = spline.m_precision;
+ m_points = spline.m_points;
+ m_validSpline = false;
+}
+
+CubicBezierSpline& CubicBezierSpline::operator=(const CubicBezierSpline& spline)
+{
+ m_precision = spline.m_precision;
+ m_points = spline.m_points;
+ return *this;
+}
+
+void CubicBezierSpline::fromString(const QString& spline)
+{
+ m_points.clear();
+ m_validSpline = false;
+
+ QStringList bpoints = spline.split('|');
+ foreach(const QString &bpoint, bpoints) {
+ QStringList points = bpoint.split('#');
+ QList <QPointF> values;
+ foreach(const QString &point, points) {
+ QStringList xy = point.split(';');
+ if (xy.count() == 2)
+ values.append(QPointF(xy.at(0).toDouble(), xy.at(1).toDouble()));
+ }
+ if (values.count() == 3) {
+ BPoint bp;
+ bp.h1 = values.at(0);
+ bp.p = values.at(1);
+ bp.h2 = values.at(2);
+ m_points.append(bp);
+ }
+ }
+
+ keepSorted();
+ validatePoints();
+}
+
+QString CubicBezierSpline::toString() const
+{
+ QStringList spline;
+ foreach(const BPoint &p, m_points) {
+ spline << (QString::number(p.h1.x()) + ";" + QString::number(p.h1.y())
+ + "#" + QString::number(p.p.x()) + ";" + QString::number(p.p.y())
+ + "#" + QString::number(p.h2.x()) + ";" + QString::number(p.h2.y()));
+ }
+ return spline.join("|");
+}
+
+int CubicBezierSpline::setPoint(int ix, const BPoint& point)
+{
+ m_points[ix] = point;
+ keepSorted();
+ validatePoints();
+ m_validSpline = false;
+ return m_points.indexOf(point); // in case it changed
+}
+
+QList <BPoint> CubicBezierSpline::points()
+{
+ return m_points;
+}
+
+void CubicBezierSpline::removePoint(int ix)
+{
+ m_points.removeAt(ix);
+ m_validSpline = false;
+}
+
+int CubicBezierSpline::addPoint(const BPoint& point)
+{
+ m_points.append(point);
+ keepSorted();
+ validatePoints();
+ m_validSpline = false;
+ return m_points.indexOf(point);
+}
+
+void CubicBezierSpline::setPrecision(int pre)
+{
+ if (pre != m_precision) {
+ m_precision = pre;
+ m_validSpline = false;
+ }
+}
+
+int CubicBezierSpline::getPrecision()
+{
+ return m_precision;
+}
+
+qreal CubicBezierSpline::value(qreal x, bool cont)
+{
+ update();
+
+ //x = qBound(m_spline.constBegin().key(), x, m_spline.constEnd().key());
+ //kDebug() << "....x" << x<<"bounddown"<<m_spline.constBegin().key()<<"up"<<m_spline.constEnd().key();
+
+ if (!cont)
+ m_i = m_spline.constBegin();
+ if (m_i != m_spline.constBegin())
+ --m_i;
+
+ double diff = qAbs(x - m_i.key());
+ double y = m_i.value();
+ while (m_i != m_spline.constEnd()) {
+ if (qAbs(x - m_i.key()) > diff)
+ break;
+
+ diff = qAbs(x - m_i.key());
+ y = m_i.value();
+ ++m_i;
+ }
+ return qBound((qreal)0.0, y, (qreal)1.0);
+}
+
+void CubicBezierSpline::validatePoints()
+{
+ BPoint p1, p2;
+ for (int i = 0; i < m_points.count() - 1; ++i) {
+ p1 = m_points.at(i);
+ p2 = m_points.at(i+1);
+ p1.h2.setX(qBound(p1.p.x(), p1.h2.x(), p2.p.x()));
+ p2.h1.setX(qBound(p1.p.x(), p2.h1.x(), p2.p.x()));
+ m_points[i] = p1;
+ m_points[i+1] = p2;
+ }
+}
+
+void CubicBezierSpline::keepSorted()
+{
+ qSort(m_points.begin(), m_points.end(), pointLessThan);
+}
+
+QPointF CubicBezierSpline::point(double t, const QList< QPointF >& points)
+{
+ // coefficients from Bernstein basis polynomial of degree 3
+ double c1 = (1-t) * (1-t) * (1-t);
+ double c2 = 3 * t * (1-t) * (1-t);
+ double c3 = 3 * t * t * (1-t);
+ double c4 = t * t * t;
+
+ return QPointF(points[0].x()*c1 + points[1].x()*c2 + points[2].x()*c3 + points[3].x()*c4,
+ points[0].y()*c1 + points[1].y()*c2 + points[2].y()*c3 + points[3].y()*c4);
+}
+
+void CubicBezierSpline::update()
+{
+ if (m_validSpline)
+ return;
+
+ m_validSpline = true;
+ m_spline.clear();
+
+ QList <QPointF> points;
+ QPointF p;
+ for (int i = 0; i < m_points.count() - 1; ++i) {
+ points.clear();
+ points << m_points.at(i).p
+ << m_points.at(i).h2
+ << m_points.at(i+1).h1
+ << m_points.at(i+1).p;
+
+ int numberOfValues = (int)((points[3].x() - points[0].x()) * m_precision);
+ if (numberOfValues == 0)
+ numberOfValues = 1;
+ double step = 1 / (double)numberOfValues;
+ double t = 0;
+ while (t <= 1) {
+ p = point(t, points);
+ m_spline.insert(p.x(), p.y());
+ t += step;
+ }
+ }
+ /*QMap<double, double>::const_iterator i = m_spline.constBegin();
+ kDebug()<<"////////////spline/////////////";
+ while (i != m_spline.constEnd()) {
+ kDebug() << i.key() << i.value();
+ ++i;
+ }
+ kDebug()<<"////////////spline/////////////end";*/
+}
+
+#include "cubicbezierspline.moc"
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2010 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 CUBICBEZIERSPLINE_H
+#define CUBICBEZIERSPLINE_H
+
+
+#include <QtCore>
+
+class BPoint
+{
+public:
+ QPointF h1; // handle 1
+ QPointF p; // point
+ QPointF h2; // handle 2
+
+ bool operator==(const BPoint &point) const { return point.h1 == h1 && point.p == p && point.h2 == h2; }
+};
+
+class CubicBezierSpline : public QObject
+{
+ Q_OBJECT
+
+public:
+ CubicBezierSpline(QObject* parent = 0);
+ CubicBezierSpline(const CubicBezierSpline &spline, QObject* parent = 0);
+ CubicBezierSpline& operator=(const CubicBezierSpline &spline);
+
+ void fromString(const QString &spline);
+ QString toString() const;
+
+ QList <BPoint> points();
+ qreal value(qreal x, bool cont = false);
+
+ int setPoint(int ix, const BPoint &point);
+ int addPoint(const BPoint &point);
+ void removePoint(int ix);
+ void setPrecision(int pre);
+ int getPrecision();
+
+private:
+ QPointF point(double t, const QList<QPointF> &points);
+ void validatePoints();
+ void keepSorted();
+ void update();
+
+ QList <BPoint> m_points;
+ QMap <double, double> m_spline;
+ QMap <double, double>::const_iterator m_i;
+ bool m_validSpline;
+ int m_precision;
+
+};
+
+#endif
#include "colortools.h"
#include "doubleparameterwidget.h"
#include "cornerswidget.h"
+#include "beziercurve/beziersplinewidget.h"
+#include "beziercurve/cubicbezierspline.h"
#include <KDebug>
#include <KLocale>
QString depends = pa.attribute("depends");
if (!depends.isEmpty())
meetDependency(paramName, type, EffectsList::parameter(e, depends));
+ } else if (type == "bezier_spline") {
+ BezierSplineWidget *widget = new BezierSplineWidget(this);
+ CubicBezierSpline spline;
+ spline.fromString(value);
+ widget->setSpline(spline);
+ m_vbox->addWidget(widget);
+ m_valueItems[paramName] = widget;
+ connect(widget, SIGNAL(modified()), this, SLOT(collectAllParameters()));
} else if (type == "corners") {
CornersWidget *corners = new CornersWidget(m_monitor, pos, isEffect, pa.attribute("factor").toInt(), this);
connect(corners, SIGNAL(checkMonitorPosition(int)), this, SIGNAL(checkMonitorPosition(int)));
QString depends = pa.attributes().namedItem("depends").nodeValue();
if (!depends.isEmpty())
meetDependency(paramName, type, EffectsList::parameter(newparam, depends));
+ } else if (type == "bezier_spline") {
+ BezierSplineWidget *widget = (BezierSplineWidget*)m_valueItems.value(paramName);
+ setValue = widget->spline().toString();
} else if (type == "corners") {
CornersWidget *corners = ((CornersWidget*)m_valueItems.value(paramName));
QString xName = pa.attributes().namedItem("xpoints").nodeValue();