reimplemented some of keyframing

This commit is contained in:
itsmattkc
2019-03-13 11:30:25 +11:00
parent ec5ee40dee
commit d84b5a7f1d
8 changed files with 195 additions and 114 deletions
+4 -5
View File
@@ -351,7 +351,7 @@ void Effect::copy_field_keyframes(EffectPtr e) {
for (int i=0;i<rows.size();i++) {
EffectRow* row = rows.at(i);
EffectRow* copy_row = e->rows.at(i);
copy_row->SetKeyframing(row->IsKeyframing());
copy_row->SetKeyframingInternal(row->IsKeyframing());
for (int j=0;j<row->FieldCount();j++) {
// Get field from this (the source) effect
EffectField* field = row->Field(j);
@@ -390,8 +390,7 @@ int Effect::gizmo_count() {
void Effect::refresh() {}
void Effect::FieldChanged() {
panel_sequence_viewer->viewer_widget->frame_update();
panel_graph_editor->update_panel();
update_ui(false);
}
void Effect::delete_self() {
@@ -545,7 +544,7 @@ void Effect::load(QXmlStreamReader& stream) {
// read keyframes
if (stream.name() == "key" && stream.isStartElement()) {
row->SetKeyframing(true);
row->SetKeyframingInternal(true);
EffectKeyframe key;
for (int k=0;k<stream.attributes().size();k++) {
@@ -623,7 +622,7 @@ void Effect::load_from_string(const QByteArray &s) {
// clear existing keyframe data
for (int i=0;i<rows.size();i++) {
EffectRow* row = rows.at(i);
row->SetKeyframing(false);
row->SetKeyframingInternal(false);
for (int j=0;j<row->FieldCount();j++) {
EffectField* field = row->Field(j);
field->keyframes.clear();
+89 -10
View File
@@ -125,26 +125,58 @@ QVariant EffectField::GetValueAt(double timecode)
double after_dbl = after_key.data.toDouble();
if (before_key.type == EFFECT_KEYFRAME_HOLD) {
// hold
// Hold keyframes will always return the previous keyframe with no interpolation
value = before_dbl;
} else if (before_key.type == EFFECT_KEYFRAME_BEZIER || after_key.type == EFFECT_KEYFRAME_BEZIER) {
// bezier interpolation
if (before_key.type == EFFECT_KEYFRAME_BEZIER && after_key.type == EFFECT_KEYFRAME_BEZIER) {
// cubic bezier
double t = cubic_t_from_x(timecode*GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), after_key.time);
value = cubic_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl+after_key.pre_handle_y, after_dbl, t);
double t = cubic_t_from_x(timecodeToFrame(timecode),
before_key.time,
before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true),
after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false),
after_key.time);
value = cubic_from_t(before_dbl,
before_dbl+before_key.post_handle_y,
after_dbl+after_key.pre_handle_y,
after_dbl,
t);
} else if (after_key.type == EFFECT_KEYFRAME_LINEAR) { // quadratic bezier
// last keyframe is the bezier one
double t = quad_t_from_x(timecode*GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate, before_key.time, before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true), after_key.time);
value = quad_from_t(before_dbl, before_dbl+before_key.post_handle_y, after_dbl, t);
double t = quad_t_from_x(timecodeToFrame(timecode),
before_key.time,
before_key.time+GetValidKeyframeHandlePosition(before_keyframe, true),
after_key.time);
value = quad_from_t(before_dbl,
before_dbl+before_key.post_handle_y,
after_dbl,
t);
} else {
// this keyframe is the bezier one
double t = quad_t_from_x(timecode*GetParentRow()->GetParentEffect()->parent_clip->sequence->frame_rate, before_key.time, after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false), after_key.time);
value = quad_from_t(before_dbl, after_dbl+after_key.pre_handle_y, after_dbl, t);
double t = quad_t_from_x(timecodeToFrame(timecode),
before_key.time,
after_key.time+GetValidKeyframeHandlePosition(after_keyframe, false),
after_key.time);
value = quad_from_t(before_dbl,
after_dbl+after_key.pre_handle_y,
after_dbl,
t);
}
} else {
// linear
// Linear interpolation (default)
value = double_lerp(before_dbl, after_dbl, progress);
}
}
return value;
@@ -175,7 +207,7 @@ QVariant EffectField::GetValueAt(double timecode)
return keyframes.first().data;
}
void EffectField::SetValueAt(double timecode, const QVariant &value)
void EffectField::SetValueAt(double time, const QVariant &value)
{
if (keyframes.isEmpty()) {
EffectKeyframe key;
@@ -185,7 +217,32 @@ void EffectField::SetValueAt(double timecode, const QVariant &value)
}
if (GetParentRow()->IsKeyframing()) {
// create keyframe here
// Create keyframe here
// Convert seconds timecode to frame
long frame_timecode = timecodeToFrame(time);
// Check array if a keyframe at this time already exists
int keyframe_index = -1;
for (int i=0;i<keyframes.size();i++) {
if (keyframes.at(i).time == frame_timecode) {
keyframe_index = i;
break;
}
}
// If keyframe doesn't exist, make it
if (keyframe_index == -1) {
EffectKeyframe key;
key.time = frame_timecode;
key.data = value;
keyframes.append(key);
} else {
EffectKeyframe& key = keyframes[keyframe_index];
key.data = value;
}
} else {
keyframes.first().data = value;
}
@@ -199,6 +256,28 @@ double EffectField::Now()
return playhead_to_clip_seconds(c, c->sequence->playhead);
}
void EffectField::PrepareDataForKeyframing(bool enabled, ComboAction *ca)
{
if (enabled) {
// Convert "perpetual" keyframe to a keyframe at this time
ca->append(new SetLong(&keyframes.first().time, keyframes.first().time, timecodeToFrame(Now())));
} else {
// Convert keyframes to one "perpetual" keyframe
// Set first keyframe to whatever the data is now
ca->append(new SetQVariant(&keyframes.first().data, keyframes.first().data, GetValueAt(Now())));
// Delete all keyframes except the first
for (int i=1;i<keyframes.size();i++) {
ca->append(new KeyframeDelete(this, 1));
}
}
}
const EffectField::EffectFieldType &EffectField::type()
{
return type_;
+10 -5
View File
@@ -53,10 +53,12 @@ public:
const QString& id();
QVariant GetValueAt(double timecode);
void SetValueAt(double timecode, const QVariant& value);
void SetValueAt(double time, const QVariant& value);
double Now();
void PrepareDataForKeyframing(bool enabled, ComboAction* ca);
int GetColumnSpan();
void SetColumnSpan(int i);
@@ -69,8 +71,15 @@ public:
bool IsEnabled();
void SetEnabled(bool e);
QVector<EffectKeyframe> keyframes;
signals:
void Changed();
void Clicked();
void EnabledChanged(bool);
private:
EffectFieldType type_;
QString id_;
@@ -82,11 +91,7 @@ private:
bool enabled_;
int colspan_;
signals:
void Changed();
void Clicked();
void EnabledChanged(bool);
};
#endif // EFFECTFIELD_H
+70 -73
View File
@@ -58,7 +58,7 @@ bool EffectRow::IsKeyframing() {
return keyframing_;
}
void EffectRow::SetKeyframing(bool b) {
void EffectRow::SetKeyframingInternal(bool b) {
if (GetParentEffect()->meta->type != EFFECT_TYPE_TRANSITION) {
keyframing_ = b;
emit KeyframingSetChanged(keyframing_);
@@ -72,28 +72,46 @@ bool EffectRow::IsSavable()
void EffectRow::SetKeyframingEnabled(bool enabled) {
if (enabled) {
ComboAction* ca = new ComboAction();
// Enable keyframing setting on this row
ca->append(new SetIsKeyframing(this, true));
set_keyframe_now(ca);
// Prepare each field's data to start keyframing
for (int i=0;i<FieldCount();i++) {
Field(i)->PrepareDataForKeyframing(true, ca);
}
olive::UndoStack.push(ca);
} else {
// Confirm with the user whether they really want to disable keyframing
if (QMessageBox::question(panel_effect_controls,
tr("Disable Keyframes"),
tr("Disabling keyframes will delete all current keyframes. Are you sure you want to do this?"),
tr("Disabling keyframes will delete all current keyframes. "
"Are you sure you want to do this?"),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
// clear
ComboAction* ca = new ComboAction();
// Prepare each field's data to stop keyframing
for (int i=0;i<FieldCount();i++) {
EffectField* f = Field(i);
for (int j=0;j<f->keyframes.size();j++) {
ca->append(new KeyframeDelete(f, 0));
}
Field(i)->PrepareDataForKeyframing(false, ca);
}
// Disable keyframing setting on this row
ca->append(new SetIsKeyframing(this, false));
olive::UndoStack.push(ca);
panel_effect_controls->update_keyframes();
} else {
SetKeyframing(true);
SetKeyframingInternal(true);
}
}
}
@@ -101,42 +119,73 @@ void EffectRow::SetKeyframingEnabled(bool enabled) {
void EffectRow::GoToPreviousKeyframe() {
long key = LONG_MIN;
Clip* c = GetParentEffect()->parent_clip;
long sequence_playhead = c->sequence->playhead;
// Used to convert clip frame number to sequence frame number
long time_adjustment = c->timeline_in() - c->clip_in();
// Loop through all of this row's fields
for (int i=0;i<FieldCount();i++) {
EffectField* f = Field(i);
// Loop through all of this field's keyframes for a keyframe EARLIER than the playhead
for (int j=0;j<f->keyframes.size();j++) {
long comp = f->keyframes.at(j).time - c->clip_in() + c->timeline_in();
if (comp < olive::ActiveSequence->playhead) {
long comp = f->keyframes.at(j).time + time_adjustment;
// Get the closest keyframe
if (comp < sequence_playhead) {
key = qMax(comp, key);
}
}
}
// If we found a keyframe less than the playhead, jump to it
if (key != LONG_MIN) panel_sequence_viewer->seek(key);
}
void EffectRow::ToggleKeyframe() {
Clip* c = GetParentEffect()->parent_clip;
long sequence_playhead = c->sequence->playhead;
// Used to convert clip frame number to sequence frame number
long time_adjustment = c->timeline_in() - c->clip_in();
QVector<EffectField*> key_fields;
QVector<int> key_field_index;
Clip* c = GetParentEffect()->parent_clip;
// See if any keyframes on any fields are at the current time
for (int j=0;j<FieldCount();j++) {
EffectField* f = Field(j);
for (int i=0;i<f->keyframes.size();i++) {
long comp = c->timeline_in() - c->clip_in() + f->keyframes.at(i).time;
if (comp == olive::ActiveSequence->playhead) {
long comp = f->keyframes.at(i).time + time_adjustment;
if (comp == sequence_playhead) {
// Cache the keyframes if they are at the current time
key_fields.append(f);
key_field_index.append(i);
}
}
}
ComboAction* ca = new ComboAction();
if (key_fields.size() == 0) {
// keyframe doesn't exist, set one
set_keyframe_now(ca);
if (key_fields.isEmpty()) {
// If we didn't find any current keyframes, create one for each field
SetKeyframeOnAllFields(ca);
} else {
// If we DID find keyframes at this time, delete them
for (int i=0;i<key_fields.size();i++) {
ca->append(new KeyframeDelete(key_fields.at(i), key_field_index.at(i)));
}
}
olive::UndoStack.push(ca);
update_ui(false);
}
@@ -160,65 +209,13 @@ void EffectRow::FocusRow() {
panel_graph_editor->set_row(this);
}
void EffectRow::set_keyframe_now(ComboAction* ca) {
// TODO address this...
/*
long time = olive::ActiveSequence->playhead
- parent_effect->parent_clip->timeline_in()
+ parent_effect->parent_clip->clip_in();
if (!just_made_unsafe_keyframe) {
EffectKeyframe key;
key.time = time;
unsafe_keys.resize(fieldCount());
unsafe_old_data.resize(fieldCount());
key_is_new.resize(fieldCount());
for (int i=0;i<fieldCount();i++) {
EffectField* f = field(i);
int exist_key = -1;
int closest_key = 0;
for (int j=0;j<f->keyframes.size();j++) {
if (f->keyframes.at(j).time == time) {
exist_key = j;
} else if (f->keyframes.at(j).time < time
&& f->keyframes.at(closest_key).time < f->keyframes.at(j).time) {
closest_key = j;
}
}
if (exist_key == -1) {
key.type = (f->keyframes.size() == 0) ? EFFECT_KEYFRAME_LINEAR : f->keyframes.at(closest_key).type;
key.data = f->GetCurrentValue();
unsafe_keys[i] = f->keyframes.size();
f->keyframes.append(key);
key_is_new[i] = true;
} else {
unsafe_keys[i] = exist_key;
key_is_new[i] = false;
}
unsafe_old_data[i] = f->GetCurrentValue();
}
just_made_unsafe_keyframe = true;
}
for (int i=0;i<fieldCount();i++) {
field(i)->keyframes[unsafe_keys.at(i)].data = field(i)->GetCurrentValue();
}
if (ca != nullptr) {
for (int i=0;i<fieldCount();i++) {
if (key_is_new.at(i)) ca->append(new KeyframeFieldSet(field(i), unsafe_keys.at(i)));
ca->append(new SetQVariant(&field(i)->keyframes[unsafe_keys.at(i)].data, unsafe_old_data.at(i), field(i)->GetCurrentValue()));
}
unsafe_keys.clear();
unsafe_old_data.clear();
just_made_unsafe_keyframe = false;
void EffectRow::SetKeyframeOnAllFields(ComboAction* ca) {
for (int i=0;i<FieldCount();i++) {
EffectField* field = Field(i);
field->SetValueAt(field->Now(), field->GetValueAt(field->Now()));
}
panel_effect_controls->update_keyframes();
*/
}
void EffectRow::delete_keyframe_at_time(ComboAction* ca, long time) {
+2 -2
View File
@@ -45,7 +45,7 @@ public:
EffectField* Field(int i);
int FieldCount();
void set_keyframe_now(ComboAction *ca);
void SetKeyframeOnAllFields(ComboAction *ca);
void delete_keyframe_at_time(ComboAction *ca, long time);
Effect* GetParentEffect();
@@ -53,7 +53,7 @@ public:
const QString& name();
bool IsKeyframing();
void SetKeyframing(bool);
void SetKeyframingInternal(bool);
bool IsSavable();
public slots:
+2 -2
View File
@@ -1092,11 +1092,11 @@ SetIsKeyframing::SetIsKeyframing(EffectRow *irow, bool ib) {
}
void SetIsKeyframing::doUndo() {
row->SetKeyframing(!b);
row->SetKeyframingInternal(!b);
}
void SetIsKeyframing::doRedo() {
row->SetKeyframing(b);
row->SetKeyframingInternal(b);
}
RefreshClips::RefreshClips(Media *m) {
+2 -1
View File
@@ -60,7 +60,8 @@ KeyframeNavigator::KeyframeNavigator(QWidget *parent, bool addLeftPad) : QWidget
connect(right_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_next_key()));
connect(right_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(clicked()));
keyframe_enable = new QPushButton(olive::icon::Clock, "", this);
keyframe_enable = new QPushButton(this);
keyframe_enable->setIcon(olive::icon::Clock);
keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
keyframe_enable->setIconSize(keyframe_enable->iconSize()*0.75);
keyframe_enable->setCheckable(true);
+16 -16
View File
@@ -28,26 +28,26 @@ class QPushButton;
class KeyframeNavigator : public QWidget
{
Q_OBJECT
Q_OBJECT
public:
KeyframeNavigator(QWidget* parent = 0, bool addLeftPad = true);
~KeyframeNavigator();
void enable_keyframes(bool);
void enable_keyframe_toggle(bool);
KeyframeNavigator(QWidget* parent = nullptr, bool addLeftPad = true);
~KeyframeNavigator();
void enable_keyframes(bool);
void enable_keyframe_toggle(bool);
signals:
void goto_previous_key();
void toggle_key();
void goto_next_key();
void keyframe_enabled_changed(bool);
void clicked();
void goto_previous_key();
void toggle_key();
void goto_next_key();
void keyframe_enabled_changed(bool);
void clicked();
private slots:
void keyframe_ui_enabled(bool);
void keyframe_ui_enabled(bool);
private:
QHBoxLayout* key_controls;
QPushButton* left_key_nav;
QPushButton* key_addremove;
QPushButton* right_key_nav;
QPushButton* keyframe_enable;
QHBoxLayout* key_controls;
QPushButton* left_key_nav;
QPushButton* key_addremove;
QPushButton* right_key_nav;
QPushButton* keyframe_enable;
};
#endif // KEYFRAMENAVIGATOR_H