From 14648d2e5107592b86df5951b926ee2abaef4e31 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 19 Aug 2018 23:03:39 +1000 Subject: [PATCH] more keyframe improvements --- effects/effect.cpp | 98 ++++++++++++++++++++++++++++--------------- effects/effect.h | 1 + playback/playback.cpp | 5 ++- playback/playback.h | 2 +- ui/keyframeview.cpp | 75 ++++++++++++++++++++++++++++----- ui/keyframeview.h | 12 +++--- ui/viewerwidget.cpp | 42 +++++++++---------- 7 files changed, 163 insertions(+), 72 deletions(-) diff --git a/effects/effect.cpp b/effects/effect.cpp index a68b4d6c9..a67e6894b 100644 --- a/effects/effect.cpp +++ b/effects/effect.cpp @@ -339,14 +339,14 @@ EffectField::EffectField(EffectRow *parent, int t) : parent_row(parent), type(t) { ComboBoxEx* cb = new ComboBoxEx(); ui_element = cb; - connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(uiElementChange())); + connect(cb, SIGNAL(activated(int)), this, SLOT(uiElementChange())); } break; case EFFECT_FIELD_FONT: { FontCombobox* fcb = new FontCombobox(); ui_element = fcb; - connect(fcb, SIGNAL(currentIndexChanged(int)), this, SLOT(uiElementChange())); + connect(fcb, SIGNAL(activated(int)), this, SLOT(uiElementChange())); } break; } @@ -414,6 +414,59 @@ void EffectField::get_keyframe_data(long frame, int* before, int* after, double* } } +void EffectField::validate_keyframe_data(long frame) { + if (parent_row->keyframing) { + int before_keyframe; + int after_keyframe; + double progress; + get_keyframe_data(frame, &before_keyframe, &after_keyframe, &progress); + + const QVariant& before_data = keyframe_data.at(before_keyframe); + switch (type) { + case EFFECT_FIELD_DOUBLE: + { + double value; + if (before_keyframe == after_keyframe) { + value = keyframe_data.at(before_keyframe).toDouble(); + } else { + double before_dbl = keyframe_data.at(before_keyframe).toDouble(); + double after_dbl = keyframe_data.at(after_keyframe).toDouble(); + value = double_lerp(before_dbl, after_dbl, progress); + } + static_cast(ui_element)->set_value(value, false); + } + break; + case EFFECT_FIELD_COLOR: + { + QColor value; + if (before_keyframe == after_keyframe) { + value = keyframe_data.at(before_keyframe).value(); + } else { + QColor before_data = keyframe_data.at(before_keyframe).value(); + QColor after_data = keyframe_data.at(after_keyframe).value(); + value = QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress)); + } + return static_cast(ui_element)->set_color(value); + } + break; + case EFFECT_FIELD_STRING: + static_cast(ui_element)->setPlainText(before_data.toString()); + break; + case EFFECT_FIELD_BOOL: + static_cast(ui_element)->setChecked(before_data.toBool()); + break; + case EFFECT_FIELD_COMBO: + static_cast(ui_element)->setCurrentIndexEx(before_data.toInt()); + break; + case EFFECT_FIELD_FONT: + static_cast(ui_element)->setCurrentTextEx(before_data.toString()); + break; + } + + + } +} + void EffectField::uiElementChange() { if (parent_row->keyframing) { parent_row->set_keyframe_now(); @@ -430,24 +483,8 @@ void EffectField::set_enabled(bool e) { } double EffectField::get_double_value(long p) { - if (parent_row->keyframing) { - int before_keyframe; - int after_keyframe; - double progress; - get_keyframe_data(p, &before_keyframe, &after_keyframe, &progress); - double value; - if (before_keyframe == after_keyframe) { - value = keyframe_data.at(before_keyframe).toDouble(); - } else { - double before_data = keyframe_data.at(before_keyframe).toDouble(); - double after_data = keyframe_data.at(after_keyframe).toDouble(); - value = double_lerp(before_data, after_data, progress); - } - static_cast(ui_element)->set_value(value, false); - return value; - } else { - return static_cast(ui_element)->value(); - } + validate_keyframe_data(p); + return static_cast(ui_element)->value(); } void EffectField::set_double_value(double v) { @@ -471,14 +508,17 @@ void EffectField::add_combo_item(const QString& name, const QVariant& data) { } int EffectField::get_combo_index(long p) { + validate_keyframe_data(p); return static_cast(ui_element)->currentIndex(); } const QVariant EffectField::get_combo_data(long p) { + validate_keyframe_data(p); return static_cast(ui_element)->currentData(); } const QString EffectField::get_combo_string(long p) { + validate_keyframe_data(p); return static_cast(ui_element)->currentText(); } @@ -491,6 +531,7 @@ void EffectField::set_combo_string(const QString& s) { } bool EffectField::get_bool_value(long p) { + validate_keyframe_data(p); return static_cast(ui_element)->isChecked(); } @@ -499,6 +540,7 @@ void EffectField::set_bool_value(bool b) { } const QString EffectField::get_string_value(long p) { + validate_keyframe_data(p); return static_cast(ui_element)->toPlainText(); } @@ -507,6 +549,7 @@ void EffectField::set_string_value(const QString& s) { } const QString EffectField::get_font_name(long p) { + validate_keyframe_data(p); return static_cast(ui_element)->currentText(); } @@ -515,20 +558,7 @@ void EffectField::set_font_name(const QString& s) { } QColor EffectField::get_color_value(long p) { - if (parent_row->keyframing) { - int before_keyframe; - int after_keyframe; - double progress; - get_keyframe_data(p, &before_keyframe, &after_keyframe, &progress); - if (before_keyframe == after_keyframe) { - return keyframe_data.at(before_keyframe).value(); - } else { - QColor before_data = keyframe_data.at(before_keyframe).value(); - QColor after_data = keyframe_data.at(after_keyframe).value(); - return QColor(lerp(before_data.red(), after_data.red(), progress), lerp(before_data.green(), after_data.green(), progress), lerp(before_data.blue(), after_data.blue(), progress)); - } - } - + validate_keyframe_data(p); return static_cast(ui_element)->get_color(); } diff --git a/effects/effect.h b/effects/effect.h index 45bc2a73f..65b6dd6b4 100644 --- a/effects/effect.h +++ b/effects/effect.h @@ -63,6 +63,7 @@ public: QVariant get_current_data(); void set_keyframe_data(int i); void get_keyframe_data(long frame, int* before, int *after, double* d); + void validate_keyframe_data(long frame); // QVariant get_keyframe_data(long p); // bool is_keyframed(long p); diff --git a/playback/playback.cpp b/playback/playback.cpp index 53f587de1..9dd9a7414 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -74,7 +74,7 @@ void cache_clip(Clip* clip, long playhead, bool write_A, bool write_B, bool rese } } -void get_clip_frame(Clip* c, long playhead) { +bool get_clip_frame(Clip* c, long playhead) { if (c->open) { long sequence_clip_time = playhead - c->timeline_in + c->clip_in; long clip_time = refactor_frame_number(sequence_clip_time, c->sequence->frame_rate, av_q2d(av_guess_frame_rate(c->formatCtx, c->stream, c->frame))); @@ -176,12 +176,15 @@ void get_clip_frame(Clip* c, long playhead) { c->texture->setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, c->comp_frame); c->texture_frame = clip_time; + + return true; } else if (!no_frame) { texture_failed = true; qDebug() << "[ERROR] Failed to retrieve frame from cache (R:" << clip_time << "| A:" << c->cache_A.offset << "-" << c->cache_A.offset+c->cache_size-1 << "| B:" << c->cache_B.offset << "-" << c->cache_B.offset+c->cache_size-1 << "| WA:" << c->cache_A.written << "| WB:" << c->cache_B.written << ")"; } } } + return false; } double playhead_to_seconds(Clip* c, long playhead) { diff --git a/playback/playback.h b/playback/playback.h index 5acc5f359..a61efa33a 100644 --- a/playback/playback.h +++ b/playback/playback.h @@ -18,7 +18,7 @@ void cache_audio_worker(Clip* c, bool write_A); void cache_video_worker(Clip* c, long playhead, ClipCache* cache); void handle_media(Sequence* sequence, long playhead, bool multithreaded); void reset_cache(Clip* c, long target_frame); -void get_clip_frame(Clip* c, long playhead); +bool get_clip_frame(Clip* c, long playhead); double playhead_to_seconds(Clip* c, long playhead); long seconds_to_clip_frame(Clip* c, double seconds); double clip_frame_to_seconds(Clip* c, long clip_frame); diff --git a/ui/keyframeview.cpp b/ui/keyframeview.cpp index 3637a2738..36d05e1da 100644 --- a/ui/keyframeview.cpp +++ b/ui/keyframeview.cpp @@ -13,7 +13,7 @@ #define KEYFRAME_SIZE 6 #define KEYFRAME_POINT_COUNT 4 -KeyframeView::KeyframeView(QWidget *parent) : QWidget(parent), mouseover(false), visible_in(0), visible_out(0) { +KeyframeView::KeyframeView(QWidget *parent) : QWidget(parent), mousedown(false), visible_in(0), visible_out(0) { setFocusPolicy(Qt::ClickFocus); setMouseTracking(true); } @@ -36,7 +36,16 @@ void KeyframeView::paintEvent(QPaintEvent*) { int keyframe_y = label->y() + (label->height()>>1) + mapFrom(panel_effect_controls, contents->mapTo(panel_effect_controls, contents->pos())).y() - e->container->title_bar->height(); for (int k=0;kkeyframe_times.size();k++) { - draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, row->keyframe_times.at(k)), keyframe_y, false); + bool keyframe_selected = false; + for (int l=0;lzoom, row->keyframe_times.at(k)-row->parent_effect->parent_clip->clip_in+(row->parent_effect->parent_clip->timeline_in-visible_in)), keyframe_y, keyframe_selected); } rows.append(row); @@ -51,21 +60,64 @@ void KeyframeView::paintEvent(QPaintEvent*) { p.drawLine(playhead_x, 0, playhead_x, height()); } - if (mouseover && mouseover_row < rowY.size()) { + /*if (mouseover && mouseover_row < rowY.size()) { draw_keyframe(p, getScreenPointFromFrame(panel_effect_controls->zoom, mouseover_frame - visible_in), rowY.at(mouseover_row), true); - } + }*/ } -void KeyframeView::draw_keyframe(QPainter &p, int x, int y, bool semiTransparent) { +void KeyframeView::draw_keyframe(QPainter &p, int x, int y, bool darker) { QPoint points[KEYFRAME_POINT_COUNT] = {QPoint(x-KEYFRAME_SIZE, y), QPoint(x, y-KEYFRAME_SIZE), QPoint(x+KEYFRAME_SIZE, y), QPoint(x, y+KEYFRAME_SIZE)}; - int alpha = (semiTransparent) ? 128 : 255; - p.setPen(QColor(0, 0, 0, alpha)); - p.setBrush(QColor(160, 160, 160, alpha)); + int color = (darker) ? 100 : 160; + p.setPen(QColor(0, 0, 0)); + p.setBrush(QColor(color, color, color)); p.drawPolygon(points, KEYFRAME_POINT_COUNT); } void KeyframeView::mousePressEvent(QMouseEvent *event) { - qDebug() << "create keyframe @ clip frame" << mouseover_frame - visible_in + (rows.at(mouseover_row)->parent_effect->parent_clip->clip_in) << "effect row" << mouseover_row; + int row_index = -1; + int keyframe_index = -1; + long frame_diff = 0; + long frame_min = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x()-KEYFRAME_SIZE); + long frame_mid = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x()); + long frame_max = getFrameFromScreenPoint(panel_effect_controls->zoom, event->x()+KEYFRAME_SIZE); + for (int i=0;iy() > rowY.at(i)-KEYFRAME_SIZE-KEYFRAME_SIZE && event->y() < rowY.at(i)+KEYFRAME_SIZE+KEYFRAME_SIZE) { + EffectRow* row = rows.at(i); + for (int j=0;jkeyframe_times.size();j++) { + long eval_keyframe_time = row->keyframe_times.at(j)-row->parent_effect->parent_clip->clip_in+(row->parent_effect->parent_clip->timeline_in-visible_in); + if (eval_keyframe_time >= frame_min && eval_keyframe_time <= frame_max) { + long eval_frame_diff = qAbs(eval_keyframe_time - frame_mid); + if (keyframe_index == -1 || eval_frame_diff < frame_diff) { + row_index = i; + keyframe_index = j; + frame_diff = eval_frame_diff; + } + } + } + break; + } + } + bool already_selected = false; + if (keyframe_index > -1) { + for (int i=0;imodifiers() & Qt::ShiftModifier)) { + selected_rows.clear(); + selected_keyframes.clear(); + } + if (keyframe_index > -1) { + selected_rows.append(row_index); + selected_keyframes.append(keyframe_index); + } + } + + update(); + mousedown = true; } void KeyframeView::mouseMoveEvent(QMouseEvent* event) { @@ -84,8 +136,11 @@ void KeyframeView::mouseMoveEvent(QMouseEvent* event) { update(); } mouseover = new_mo;*/ + if (mousedown) { + + } } void KeyframeView::mouseReleaseEvent(QMouseEvent* event) { - + mousedown = false; } diff --git a/ui/keyframeview.h b/ui/keyframeview.h index 8382ce015..a77442c71 100644 --- a/ui/keyframeview.h +++ b/ui/keyframeview.h @@ -17,17 +17,19 @@ public: long visible_in; long visible_out; private: + QVector selected_rows; + QVector selected_keyframes; QVector rowY; QVector rows; void mousePressEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); void mouseReleaseEvent(QMouseEvent *event); void paintEvent(QPaintEvent *event); - void draw_keyframe(QPainter& p, int x, int y, bool semiTransparent); - bool enable_reload; - bool mouseover; - long mouseover_frame; - int mouseover_row; + void draw_keyframe(QPainter& p, int x, int y, bool darker); + bool mousedown; + + int drag_row_index; + int drag_keyframe_index; }; #endif // KEYFRAMEVIEW_H diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 6aa7508d4..884a9d716 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -172,33 +172,33 @@ void ViewerWidget::compose_sequence(QVector& nests, bool render_audio) { if (flip) half_height = -half_height; glOrtho(-half_width, half_width, half_height, -half_height, -1, 1); int anchor_x = ms->video_width/2; - int anchor_y = ms->video_height/2; + int anchor_y = ms->video_height/2; - QOpenGLShaderProgram shader; + QOpenGLShaderProgram shader; - for (int j=0;jeffects.size();j++) { - if (c->effects.at(j)->enable_opengl && c->effects.at(j)->is_enabled()) c->effects.at(j)->process_gl(panel_timeline->playhead-c->timeline_in+c->clip_in, shader, &anchor_x, &anchor_y); - } + for (int j=0;jeffects.size();j++) { + if (c->effects.at(j)->enable_opengl && c->effects.at(j)->is_enabled()) c->effects.at(j)->process_gl(panel_timeline->playhead-c->timeline_in+c->clip_in, shader, &anchor_x, &anchor_y); + } - if (c->opening_transition != NULL) { - int transition_progress = playhead - c->timeline_in; - if (transition_progress < c->opening_transition->length) { - c->opening_transition->process_transition((double)transition_progress/(double)c->opening_transition->length); - } - } + if (c->opening_transition != NULL) { + int transition_progress = playhead - c->timeline_in; + if (transition_progress < c->opening_transition->length) { + c->opening_transition->process_transition((double)transition_progress/(double)c->opening_transition->length); + } + } - if (c->closing_transition != NULL) { - int transition_progress = c->closing_transition->length - (playhead - c->timeline_in - c->getLength() + c->closing_transition->length); - if (transition_progress < c->closing_transition->length) { - c->closing_transition->process_transition((double)transition_progress/(double)c->closing_transition->length); - } - } + if (c->closing_transition != NULL) { + int transition_progress = c->closing_transition->length - (playhead - c->timeline_in - c->getLength() + c->closing_transition->length); + if (transition_progress < c->closing_transition->length) { + c->closing_transition->process_transition((double)transition_progress/(double)c->closing_transition->length); + } + } int anchor_right = ms->video_width - anchor_x; int anchor_bottom = ms->video_height - anchor_y; - bool use_gl_shaders = shader.link(); - if (use_gl_shaders) shader.bind(); + bool use_gl_shaders = shader.link(); + if (use_gl_shaders) shader.bind(); c->texture->bind(); @@ -213,9 +213,9 @@ void ViewerWidget::compose_sequence(QVector& nests, bool render_audio) { glVertex2f(-anchor_x, anchor_bottom); glEnd(); - c->texture->release(); + c->texture->release(); - if (use_gl_shaders) shader.release(); + if (use_gl_shaders) shader.release(); } } else if (render_audio && c->stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&