Fix various geometry keyframe regressions in monitor:

-show again path of keyframe centers in monitor
-fix incorrect path interpolation for smooth keyframes
parent d925b8e3
......@@ -917,76 +917,53 @@ QVariant KeyframeModel::getInterpolatedValue(const GenTime &pos) const
if (m_keyframeList.size() == 0) {
return QVariant();
}
auto next = m_keyframeList.upper_bound(pos);
if (next == m_keyframeList.cbegin()) {
return (m_keyframeList.cbegin())->second.second;
} else if (next == m_keyframeList.cend()) {
auto it = m_keyframeList.cend();
--it;
return it->second.second;
}
auto prev = next;
--prev;
// We now have surrounding keyframes, we use mlt to compute the value
Mlt::Properties prop;
bool useOpacity = true;
Mlt::Properties mlt_prop;
QString animData;
int in = 0;
int out = 0;
bool useOpacity = false;
if (auto ptr = m_model.lock()) {
ptr->passProperties(prop);
if (m_paramType == ParamType::AnimatedRect) {
useOpacity = ptr->data(m_index, AssetParameterModel::OpacityRole).toBool();
}
ptr->passProperties(mlt_prop);
in = ptr->data(m_index, AssetParameterModel::ParentInRole).toInt();
out = ptr->data(m_index, AssetParameterModel::ParentDurationRole).toInt();
useOpacity = ptr->data(m_index, AssetParameterModel::OpacityRole).toBool();
animData = ptr->data(m_index, AssetParameterModel::ValueRole).toString();
}
QLocale locale;
int p = pos.frames(pCore->getCurrentFps());
if (m_paramType == ParamType::KeyframeParam) {
prop.anim_set("keyframe", prev->second.second.toDouble(), prev->first.frames(pCore->getCurrentFps()), next->first.frames(pCore->getCurrentFps()),
convertToMltType(prev->second.first));
prop.anim_set("keyframe", next->second.second.toDouble(), next->first.frames(pCore->getCurrentFps()), next->first.frames(pCore->getCurrentFps()),
convertToMltType(next->second.first));
return QVariant(prop.anim_get_double("keyframe", p));
} else if (m_paramType == ParamType::AnimatedRect) {
QStringList vals = prev->second.second.toString().split(QLatin1Char(' '));
if (vals.count() >= 4) {
mlt_rect rect;
rect.x = vals.at(0).toInt();
rect.y = vals.at(1).toInt();
rect.w = vals.at(2).toInt();
rect.h = vals.at(3).toInt();
if (useOpacity) {
if (vals.count()) {
rect.o = locale.toDouble(vals.at(4));
} else {
rect.o = 1;
}
}
prop.anim_set("keyframe", rect, prev->first.frames(pCore->getCurrentFps()), next->first.frames(pCore->getCurrentFps()),
convertToMltType(prev->second.first));
if (!animData.isEmpty()) {
mlt_prop.set("key", animData.toUtf8().constData());
// This is a fake query to force the animation to be parsed
(void)mlt_prop.anim_get_double("key", 0, out);
return QVariant(mlt_prop.anim_get_double("key", pos.frames(pCore->getCurrentFps())));
}
vals = next->second.second.toString().split(QLatin1Char(' '));
if (vals.count() >= 4) {
mlt_rect rect;
rect.x = vals.at(0).toInt();
rect.y = vals.at(1).toInt();
rect.w = vals.at(2).toInt();
rect.h = vals.at(3).toInt();
return QVariant();
} else if (m_paramType == ParamType::AnimatedRect) {
if (!animData.isEmpty()) {
QLocale locale;
mlt_prop.set("key", animData.toUtf8().constData());
// This is a fake query to force the animation to be parsed
(void)mlt_prop.anim_get_double("key", 0, out);
mlt_rect rect = mlt_prop.anim_get_rect("key", pos.frames(pCore->getCurrentFps()));
QString res = QStringLiteral("%1 %2 %3 %4").arg((int)rect.x).arg((int)rect.y).arg((int)rect.w).arg((int)rect.h);
if (useOpacity) {
if (vals.count() > 4) {
rect.o = locale.toDouble(vals.at(4));
} else {
rect.o = 1;
}
res.append(QStringLiteral(" %1").arg(locale.toString(rect.o)));
}
prop.anim_set("keyframe", rect, next->first.frames(pCore->getCurrentFps()), next->first.frames(pCore->getCurrentFps()),
convertToMltType(next->second.first));
}
mlt_rect rect = prop.anim_get_rect("keyframe", p);
QString res = QStringLiteral("%1 %2 %3 %4").arg((int)rect.x).arg((int)rect.y).arg((int)rect.w).arg((int)rect.h);
if (useOpacity) {
res.append(QStringLiteral(" %1").arg(locale.toString(rect.o)));
return QVariant(res);
}
return QVariant(res);
return QVariant();
} else if (m_paramType == ParamType::Roto_spline) {
// interpolate
auto next = m_keyframeList.upper_bound(pos);
if (next == m_keyframeList.cbegin()) {
return (m_keyframeList.cbegin())->second.second;
} else if (next == m_keyframeList.cend()) {
auto it = m_keyframeList.cend();
--it;
return it->second.second;
}
auto prev = next;
--prev;
QSize frame = pCore->getCurrentFrameSize();
QList<BPoint> p1 = RotoHelper::getPoints(prev->second.second, frame);
QList<BPoint> p2 = RotoHelper::getPoints(next->second.second, frame);
......@@ -995,7 +972,7 @@ QVariant KeyframeModel::getInterpolatedValue(const GenTime &pos) const
// - equal to 1 on next keyframe
qreal relPos = 0;
if (next->first != prev->first) {
relPos = (p - prev->first.frames(pCore->getCurrentFps())) / (qreal)(((next->first - prev->first).frames(pCore->getCurrentFps())));
relPos = (pos.frames(pCore->getCurrentFps()) - prev->first.frames(pCore->getCurrentFps())) / (qreal)(((next->first - prev->first).frames(pCore->getCurrentFps())));
}
int count = qMin(p1.count(), p2.count());
QList<QVariant> vlist;
......
......@@ -262,6 +262,14 @@ bool KeyframeModelList::isEmpty() const
return (m_parameters.size() == 0 || m_parameters.begin()->second->rowCount() == 0);
}
int KeyframeModelList::count() const
{
READ_LOCK();
if (m_parameters.size() > 0)
return m_parameters.begin()->second->rowCount();
return 0;
}
Keyframe KeyframeModelList::getNextKeyframe(const GenTime &pos, bool *ok) const
{
READ_LOCK();
......@@ -485,3 +493,13 @@ void KeyframeModelList::checkConsistency()
}
}
}
GenTime KeyframeModelList::getPosAtIndex(int ix)
{
QList<GenTime> positions = m_parameters.begin()->second->getKeyframePos();
std::sort(positions.begin(), positions.end());
if (ix < 0 || ix >= positions.count()) {
return GenTime();
}
return positions.at(ix);
}
......@@ -96,6 +96,9 @@ public:
/* @brief Returns true if we only have no keyframe
*/
bool isEmpty() const;
/* @brief Returns the number of keyframes
*/
int count() const;
/* @brief Returns the keyframe located after given position.
If there is a keyframe at given position it is ignored.
......@@ -136,6 +139,9 @@ public:
/** @brief Parent item size change, update keyframes*/
void resizeKeyframes(int oldIn, int oldOut, int in, int out, int offset, bool adjustFromEnd, Fun &undo, Fun &redo);
/** @brief Return position of the nth keyframe (ix = nth)*/
GenTime getPosAtIndex(int ix);
/** @brief Check that all keyframable parameters have the same keyframes on loading
* (that's how our model works) */
void checkConsistency();
......
......@@ -21,9 +21,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "keyframemonitorhelper.hpp"
#include "assets/model/assetparametermodel.hpp"
#include "assets/keyframes/model/keyframemodellist.hpp"
#include "monitor/monitor.h"
#include <utility>
#include <core.h>
KeyframeMonitorHelper::KeyframeMonitorHelper(Monitor *monitor, std::shared_ptr<AssetParameterModel> model, const QPersistentModelIndex &index, QObject *parent)
: QObject(parent)
, m_monitor(monitor)
......@@ -52,3 +54,79 @@ void KeyframeMonitorHelper::addIndex(const QPersistentModelIndex &index)
{
m_indexes << index;
}
void KeyframeMonitorHelper::refreshParams(int pos)
{
QVariantList points;
QVariantList types;
std::shared_ptr<KeyframeModelList> keyframes = m_model->getKeyframeModel();
for (const auto &ix : m_indexes) {
auto type = m_model->data(ix, AssetParameterModel::TypeRole).value<ParamType>();
if (type != ParamType::AnimatedRect) {
continue;
}
KeyframeModel *kfr = keyframes->getKeyModel(ix);
bool ok;
Keyframe kf = kfr->getNextKeyframe(GenTime(-1), &ok);
while (ok) {
if (kf.second == KeyframeType::Curve) {
types << 1;
} else {
types << 0;
}
QString rectData = kfr->getInterpolatedValue(kf.first).toString();
QStringList data = rectData.split(QLatin1Char(' '));
if (data.size() > 3) {
QRectF r(data.at(0).toInt(), data.at(1).toInt(), data.at(2).toInt(), data.at(3).toInt());
points.append(QVariant(r.center()));
}
kf = kfr->getNextKeyframe(kf.first, &ok);
}
break;
}
if (m_monitor) {
m_monitor->setUpEffectGeometry(QRect(), points, types);
}
}
void KeyframeMonitorHelper::slotUpdateFromMonitorData(const QVariantList &centers)
{
std::shared_ptr<KeyframeModelList> keyframes = m_model->getKeyframeModel();
if (centers.count() != keyframes->count()) {
qDebug() << "* * * *CENTER POINTS MISMATCH, aborting edit";
return;
}
for (const auto &ix : m_indexes) {
auto type = m_model->data(ix, AssetParameterModel::TypeRole).value<ParamType>();
if (type != ParamType::AnimatedRect) {
continue;
}
KeyframeModel *kfr = keyframes->getKeyModel(ix);
bool ok;
Keyframe kf = kfr->getNextKeyframe(GenTime(-1), &ok);
int i = 0;
while (ok) {
QString rectData = kfr->getInterpolatedValue(kf.first).toString();
QStringList data = rectData.split(QLatin1Char(' '));
if (data.size() > 3) {
QRectF r(data.at(0).toInt(), data.at(1).toInt(), data.at(2).toInt(), data.at(3).toInt());
QPointF pt(r.center());
QPointF expected = centers.at(i).toPointF();
if (pt != expected) {
// Center rect to new pos
QPointF offset = expected - pt;
r.translate(offset);
QString res = QString("%1 %2 %3 %4").arg((int)r.x()).arg((int)r.y()).arg((int)r.width()).arg((int)r.height());
if (data.size() > 4) {
res.append(QString(" %1").arg(data.at(4)));
}
kfr->updateKeyframe(kf.first, res);
}
}
kf = kfr->getNextKeyframe(kf.first, &ok);
i++;
}
break;
}
}
......@@ -53,7 +53,7 @@ public:
bool connectMonitor(bool activate);
/** @brief Send data update to the monitor
*/
virtual void refreshParams(int pos) = 0;
virtual void refreshParams(int pos);
protected:
Monitor *m_monitor;
......@@ -64,7 +64,7 @@ protected:
bool m_active;
private slots:
virtual void slotUpdateFromMonitorData(const QVariantList &v) = 0;
virtual void slotUpdateFromMonitorData(const QVariantList &v);
public slots:
/** @brief For classes that manage several parameters, add a param index to the list
......
......@@ -21,6 +21,7 @@
#include "assets/keyframes/model/corners/cornershelper.hpp"
#include "assets/keyframes/model/keyframemodellist.hpp"
#include "assets/keyframes/model/rotoscoping/rotohelper.hpp"
#include "assets/keyframes/model/keyframemonitorhelper.hpp"
#include "assets/keyframes/view/keyframeview.hpp"
#include "assets/model/assetparametermodel.hpp"
#include "assets/view/widgets/keyframeimport.h"
......@@ -98,6 +99,7 @@ KeyframeWidget::KeyframeWidget(std::shared_ptr<AssetParameterModel> model, QMode
Monitor *monitor = pCore->getMonitor(m_model->monitorId);
connect(monitor, &Monitor::seekPosition, this, &KeyframeWidget::monitorSeek, Qt::UniqueConnection);
connect(monitor, &Monitor::seekToKeyframe, this, &KeyframeWidget::slotSeekToKeyframe, Qt::UniqueConnection);
m_time = new TimecodeDisplay(pCore->timecode(), this);
m_time->setRange(0, duration - 1);
......@@ -342,10 +344,11 @@ void KeyframeWidget::addParameter(const QPersistentModelIndex &index)
int inPos = m_model->data(index, AssetParameterModel::ParentInRole).toInt();
QPair<int, int> range(inPos, inPos + m_model->data(index, AssetParameterModel::ParentDurationRole).toInt());
const QString value = m_keyframes->getInterpolatedValue(getPosition(), index).toString();
m_monitorHelper = new KeyframeMonitorHelper(pCore->getMonitor(m_model->monitorId), m_model, index, this);
QRect rect;
double opacity = 0;
QStringList vals = value.split(QLatin1Char(' '));
if (vals.count() >= 4) {
if (vals.count() > 3) {
rect = QRect(vals.at(0).toInt(), vals.at(1).toInt(), vals.at(2).toInt(), vals.at(3).toInt());
if (vals.count() > 4) {
opacity = locale.toDouble(vals.at(4));
......@@ -506,3 +509,10 @@ void KeyframeWidget::slotRemoveNextKeyframes()
int pos = m_time->getValue() + m_model->data(m_index, AssetParameterModel::ParentInRole).toInt();
m_keyframes->removeNextKeyframes(GenTime(pos, pCore->getCurrentFps()));
}
void KeyframeWidget::slotSeekToKeyframe(int ix)
{
int pos = m_keyframes->getPosAtIndex(ix).frames(pCore->getCurrentFps());
slotSetPosition(pos, true);
}
......@@ -81,6 +81,7 @@ private slots:
void slotCopyKeyframes();
void slotImportKeyframes();
void slotRemoveNextKeyframes();
void slotSeekToKeyframe(int ix);
private:
QVBoxLayout *m_lay;
......
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