From d433289b4adcf7d0db084964e8bc0b670575c33b Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 19 Jan 2019 03:02:00 +1100 Subject: [PATCH] validate keyframes to prevent overlapping --- main.cpp | 2 ++ project/effectfield.cpp | 54 ++++++++++++++++++++++++++++++++++++++--- project/effectfield.h | 2 ++ ui/graphview.cpp | 12 ++++++--- 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/main.cpp b/main.cpp index 4d3ddd33f..eca3fc36f 100644 --- a/main.cpp +++ b/main.cpp @@ -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 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 { diff --git a/project/effectfield.h b/project/effectfield.h index c31fddffd..278fdd8d7 100644 --- a/project/effectfield.h +++ b/project/effectfield.h @@ -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); diff --git a/ui/graphview.cpp b/ui/graphview.cpp index be13a5f0a..30cee5707 100644 --- a/ui/graphview.cpp +++ b/ui/graphview.cpp @@ -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) ); }