validate keyframes to prevent overlapping

This commit is contained in:
itsmattkc
2019-01-19 03:02:00 +11:00
parent 61f5e131b9
commit d433289b4a
4 changed files with 62 additions and 8 deletions
+2
View File
@@ -20,7 +20,9 @@ int main(int argc, char *argv[]) {
bool launch_fullscreen = false;
QString load_proj;
#ifndef NODEBUG
qInstallMessageHandler(debug_message_handler);
#endif
if (argc > 1) {
for (int i=1;i<argc;i++) {
+50 -4
View File
@@ -86,7 +86,53 @@ EffectField::EffectField(EffectRow *parent, int t, const QString &i) :
connect(efc, SIGNAL(changed()), this, SLOT(ui_element_change()));
}
break;
}
}
}
double EffectField::get_validated_keyframe_handle(int key, bool post) {
int comp_key = -1;
// find keyframe before or after this one
for (int i=0;i<keyframes.size();i++) {
if (i != key
&& ((keyframes.at(i).time > keyframes.at(key).time) == post)
&& (comp_key == -1
|| ((keyframes.at(i).time < keyframes.at(comp_key).time) == post))) {
// compare with next keyframe for post or previous frame for pre
comp_key = i;
}
}
double adjusted_key = post ? keyframes.at(key).post_handle_x : keyframes.at(key).pre_handle_x;
// if this is the earliest/latest keyframe, no validation is required
if (comp_key == -1) {
return adjusted_key;
}
double comp = keyframes.at(comp_key).time - keyframes.at(key).time;
// if comp keyframe is bezier, validate with its accompanying handle
if (keyframes.at(comp_key).type == KEYFRAME_TYPE_BEZIER) {
double relative_comp_handle = comp + (post ? keyframes.at(comp_key).pre_handle_x : keyframes.at(comp_key).post_handle_x);
// return an average
if ((post && keyframes.at(key).post_handle_x > relative_comp_handle)
|| (!post && keyframes.at(key).pre_handle_x < relative_comp_handle)) {
adjusted_key = (adjusted_key + relative_comp_handle)*0.5;
}
}
// don't let handle go beyond the compare keyframe's time
if (post == (adjusted_key > comp)) {
return comp;
}
if (post == (adjusted_key < 0)) {
return 0;
}
// original value is valid
return adjusted_key;
}
QVariant EffectField::get_previous_data() {
@@ -203,15 +249,15 @@ QVariant EffectField::validate_keyframe_data(double timecode, bool async) {
// bezier interpolation
if (before_key.type == KEYFRAME_TYPE_BEZIER && after_key.type == KEYFRAME_TYPE_BEZIER) {
// cubic bezier
double t = cubic_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+before_key.post_handle_x, after_key.time+after_key.pre_handle_x, after_key.time);
double t = cubic_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+get_validated_keyframe_handle(before_keyframe, true), after_key.time+get_validated_keyframe_handle(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 == KEYFRAME_TYPE_LINEAR) { // quadratic bezier
// last keyframe is the bezier one
double t = quad_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+before_key.post_handle_x, after_key.time);
double t = quad_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, before_key.time+get_validated_keyframe_handle(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*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, after_key.time+after_key.pre_handle_x, after_key.time);
double t = quad_t_from_x(timecode*parent_row->parent_effect->parent_clip->sequence->frame_rate, before_key.time, after_key.time+get_validated_keyframe_handle(after_keyframe, false), after_key.time);
value = quad_from_t(before_dbl, after_dbl+after_key.pre_handle_y, after_dbl, t);
}
} else {
+2
View File
@@ -26,6 +26,8 @@ public:
int type;
QString id;
double get_validated_keyframe_handle(int key, bool post);
QVariant get_previous_data();
QVariant get_current_data();
double frameToTimecode(long frame);
+8 -4
View File
@@ -237,6 +237,10 @@ void GraphView::paintEvent(QPaintEvent *) {
p.drawLine(0, key_y, key_x, key_y);
} else {
const EffectKeyframe& last_key = field->keyframes.at(sorted_keys.at(j-1));
double pre_handle = field->get_validated_keyframe_handle(sorted_keys.at(j), false);
double last_post_handle = field->get_validated_keyframe_handle(sorted_keys.at(j-1), true);
if (last_key.type == KEYFRAME_TYPE_HOLD) {
// hold
p.drawLine(last_key_x, last_key_y, key_x, last_key_y);
@@ -247,20 +251,20 @@ void GraphView::paintEvent(QPaintEvent *) {
if (last_key.type == KEYFRAME_TYPE_BEZIER && key.type == KEYFRAME_TYPE_BEZIER) {
// cubic bezier
bezier_path.cubicTo(
QPointF(last_key_x+last_key.post_handle_x*zoom, last_key_y-last_key.post_handle_y*zoom),
QPointF(key_x+key.pre_handle_x*zoom, key_y-key.pre_handle_y*zoom),
QPointF(last_key_x+last_post_handle*zoom, last_key_y-last_key.post_handle_y*zoom),
QPointF(key_x+pre_handle*zoom, key_y-key.pre_handle_y*zoom),
QPointF(key_x, key_y)
);
} else if (key.type == KEYFRAME_TYPE_LINEAR) { // quadratic bezier
// last keyframe is the bezier one
bezier_path.quadTo(
QPointF(last_key_x+last_key.post_handle_x*zoom, last_key_y-last_key.post_handle_y*zoom),
QPointF(last_key_x+last_post_handle*zoom, last_key_y-last_key.post_handle_y*zoom),
QPointF(key_x, key_y)
);
} else {
// this keyframe is the bezier one
bezier_path.quadTo(
QPointF(key_x+key.pre_handle_x*zoom, key_y-key.pre_handle_y*zoom),
QPointF(key_x+pre_handle*zoom, key_y-key.pre_handle_y*zoom),
QPointF(key_x, key_y)
);
}