diff --git a/dialogs/exportdialog.cpp b/dialogs/exportdialog.cpp index b012f506b..5ed83c0fd 100644 --- a/dialogs/exportdialog.cpp +++ b/dialogs/exportdialog.cpp @@ -554,9 +554,9 @@ void ExportDialog::update_progress_bar(int value, qint64 remaining_ms) { } void ExportDialog::cancel_render() { - panel_sequence_viewer->viewer_widget->force_quit = true; et->continueEncode = false; cancelled = true; + et->wake(); } void ExportDialog::vcodec_changed(int index) { diff --git a/io/exportthread.cpp b/io/exportthread.cpp index 92c6dc6ee..5e4f1a34e 100644 --- a/io/exportthread.cpp +++ b/io/exportthread.cpp @@ -355,20 +355,14 @@ void ExportThread::run() { } if (video_enabled) { do { + // TODO optimize by rendering the next frame while encoding the last renderer->start_render(nullptr, sequence, nullptr, video_frame->data[0]); waitCond.wait(&mutex); + if (!continueEncode) break; } while (renderer->did_texture_fail()); + if (!continueEncode) break; } - /*if (sequence->playhead == start_frame) { - // render first frame - if (video_enabled) { - qDebug() << "FIRST FRAME start video thread"; - renderer->start_render(nullptr, sequence, nullptr, video_frame->data[0]); - } - sequence->playhead++; - }*/ - // encode last frame while rendering next frame double timecode_secs = (double) (sequence->playhead-start_frame) / sequence->frame_rate; if (video_enabled) { diff --git a/io/exportthread.h b/io/exportthread.h index 8e4fc085f..b06ddc2c2 100644 --- a/io/exportthread.h +++ b/io/exportthread.h @@ -54,7 +54,7 @@ public: bool continueEncode; signals: void progress_changed(int value, qint64 remaining_ms); -private slots: +public slots: void wake(); private: bool encode(AVFormatContext* ofmt_ctx, AVCodecContext* codec_ctx, AVFrame* frame, AVPacket* packet, AVStream* stream, bool rescale); diff --git a/ui/keyframenavigator.cpp b/ui/keyframenavigator.cpp index b3bb95c32..8115ed42f 100644 --- a/ui/keyframenavigator.cpp +++ b/ui/keyframenavigator.cpp @@ -14,50 +14,58 @@ KeyframeNavigator::KeyframeNavigator(QWidget *parent) : QWidget(parent) { QSize clock_size(clock_size_val, clock_size_val); QSize button_size(button_size_val, button_size_val); - key_controls = new QHBoxLayout(); - key_controls->setSpacing(0); - key_controls->setMargin(0); + key_controls = new QHBoxLayout(); + key_controls->setSpacing(0); + key_controls->setMargin(0); //key_controls->addStretch(); - setLayout(key_controls); + setLayout(key_controls); - left_key_nav = new QPushButton(); - left_key_nav->setIcon(QIcon(":/icons/tri-left.png")); - left_key_nav->setMaximumSize(button_size); - left_key_nav->setIconSize(icon_size); - left_key_nav->setVisible(false); - key_controls->addWidget(left_key_nav); - connect(left_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_previous_key())); + left_key_nav = new QPushButton(); + left_key_nav->setIcon(QIcon(":/icons/tri-left.png")); + left_key_nav->setMaximumSize(button_size); + left_key_nav->setIconSize(icon_size); + left_key_nav->setVisible(false); + key_controls->addWidget(left_key_nav); + connect(left_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_previous_key())); connect(left_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(clicked())); - key_addremove = new QPushButton(); - key_addremove->setIcon(QIcon(":/icons/diamond.png")); - key_addremove->setMaximumSize(button_size); - key_addremove->setIconSize(QSize(8, 8)); - key_addremove->setVisible(false); - key_controls->addWidget(key_addremove); - connect(key_addremove, SIGNAL(clicked(bool)), this, SIGNAL(toggle_key())); + key_addremove = new QPushButton(); + key_addremove->setIcon(QIcon(":/icons/diamond.png")); + key_addremove->setMaximumSize(button_size); + key_addremove->setIconSize(QSize(8, 8)); + key_addremove->setVisible(false); + key_controls->addWidget(key_addremove); + connect(key_addremove, SIGNAL(clicked(bool)), this, SIGNAL(toggle_key())); connect(key_addremove, SIGNAL(clicked(bool)), this, SIGNAL(clicked())); - right_key_nav = new QPushButton(); - right_key_nav->setIcon(QIcon(":/icons/tri-right.png")); - right_key_nav->setMaximumSize(button_size); - right_key_nav->setIconSize(icon_size); - right_key_nav->setVisible(false); - key_controls->addWidget(right_key_nav); - connect(right_key_nav, SIGNAL(clicked(bool)), this, SIGNAL(goto_next_key())); + right_key_nav = new QPushButton(); + right_key_nav->setIcon(QIcon(":/icons/tri-right.png")); + right_key_nav->setMaximumSize(button_size); + right_key_nav->setIconSize(icon_size); + right_key_nav->setVisible(false); + key_controls->addWidget(right_key_nav); + 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(QIcon(":/icons/clock.png"), ""); - keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); - keyframe_enable->setMaximumSize(button_size); + keyframe_enable = new QPushButton(QIcon(":/icons/clock.png"), ""); + keyframe_enable->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); + keyframe_enable->setMaximumSize(button_size); keyframe_enable->setIconSize(clock_size); - keyframe_enable->setCheckable(true); - keyframe_enable->setToolTip(tr("Enable Keyframes")); + keyframe_enable->setCheckable(true); + keyframe_enable->setToolTip(tr("Enable Keyframes")); connect(keyframe_enable, SIGNAL(clicked(bool)), this, SIGNAL(keyframe_enabled_changed(bool))); - connect(keyframe_enable, SIGNAL(toggled(bool)), this, SLOT(keyframe_ui_enabled(bool))); + connect(keyframe_enable, SIGNAL(toggled(bool)), this, SLOT(keyframe_ui_enabled(bool))); connect(keyframe_enable, SIGNAL(clicked(bool)), this, SIGNAL(clicked())); - key_controls->addWidget(keyframe_enable); + key_controls->addWidget(keyframe_enable); +} + +KeyframeNavigator::~KeyframeNavigator() { + delete keyframe_enable; + delete right_key_nav; + delete key_addremove; + delete left_key_nav; + delete key_controls; } void KeyframeNavigator::enable_keyframes(bool b) { @@ -69,7 +77,7 @@ void KeyframeNavigator::enable_keyframe_toggle(bool b) { } void KeyframeNavigator::keyframe_ui_enabled(bool enabled) { - left_key_nav->setVisible(enabled); - key_addremove->setVisible(enabled); - right_key_nav->setVisible(enabled); + left_key_nav->setVisible(enabled); + key_addremove->setVisible(enabled); + right_key_nav->setVisible(enabled); } diff --git a/ui/keyframenavigator.h b/ui/keyframenavigator.h index 6b6eaee85..d81f87f26 100644 --- a/ui/keyframenavigator.h +++ b/ui/keyframenavigator.h @@ -8,25 +8,26 @@ class QPushButton; class KeyframeNavigator : public QWidget { - Q_OBJECT + Q_OBJECT public: - KeyframeNavigator(QWidget* parent = 0); - void enable_keyframes(bool); + KeyframeNavigator(QWidget* parent = 0); + ~KeyframeNavigator(); + void enable_keyframes(bool); void enable_keyframe_toggle(bool); signals: - void goto_previous_key(); - void toggle_key(); - void goto_next_key(); + 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 diff --git a/ui/renderfunctions.cpp b/ui/renderfunctions.cpp index 43381a603..c719acdda 100644 --- a/ui/renderfunctions.cpp +++ b/ui/renderfunctions.cpp @@ -125,8 +125,6 @@ GLuint compose_sequence(Viewer* viewer, glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo); } - bool drawn_gizmos = false; - Sequence* s = seq; long playhead = s->playhead; @@ -332,12 +330,10 @@ GLuint compose_sequence(Viewer* viewer, } } - if (!rendering) { - if (selected_effect != nullptr) { - gizmos = &selected_effect; - } else if (is_clip_selected(c, true)) { - gizmos = &first_gizmo_effect; - } + if (selected_effect != nullptr) { + (*gizmos) = selected_effect; + } else if (is_clip_selected(c, true)) { + (*gizmos) = first_gizmo_effect; } if (c->get_opening_transition() != nullptr) { @@ -429,17 +425,16 @@ GLuint compose_sequence(Viewer* viewer, glBindTexture(GL_TEXTURE_2D, 0); // unbind texture - // TODO restore this function - /*if ((*gizmos) != nullptr && !drawn_gizmos && nests.isEmpty()) { + // prepare gizmos + if ((*gizmos) != nullptr + && nests.isEmpty() + && ((*gizmos) == first_gizmo_effect + || (*gizmos) == selected_effect)) { (*gizmos)->gizmo_draw(timecode, coords); // set correct gizmo coords - (*gizmos)->gizmo_world_to_screen(); - - drawn_gizmos = true; - }*/ + (*gizmos)->gizmo_world_to_screen(); // convert gizmo coords to screen coords + } if (!nests.isEmpty()) { -// nests.last()->fbo[0]->release(); -// if (default_fbo != nullptr) default_fbo->bind(); ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo); } diff --git a/ui/renderthread.cpp b/ui/renderthread.cpp index eca133588..8ac33d1a5 100644 --- a/ui/renderthread.cpp +++ b/ui/renderthread.cpp @@ -12,6 +12,7 @@ RenderThread::RenderThread() : frameBuffer(0), texColorBuffer(0), + gizmos(nullptr), share_ctx(nullptr), ctx(nullptr), seq(nullptr), @@ -106,9 +107,8 @@ void RenderThread::paint() { glEnable(GL_BLEND); glEnable(GL_DEPTH); - Effect* gizmos; // does nothing yet + gizmos = nullptr; QVector nests; - compose_sequence(nullptr, ctx, seq, nests, true, false, &gizmos, texture_failed, false); if (!save_fn.isEmpty()) { diff --git a/ui/renderthread.h b/ui/renderthread.h index 3f88ba026..e3c95105b 100644 --- a/ui/renderthread.h +++ b/ui/renderthread.h @@ -9,6 +9,7 @@ #include struct Sequence; +class Effect; class RenderThread : public QThread { Q_OBJECT @@ -19,6 +20,7 @@ public: QMutex mutex; GLuint frameBuffer; GLuint texColorBuffer; + Effect* gizmos; void paint(); void start_render(QOpenGLContext* share, Sequence* s, const QString &save = nullptr, GLvoid *pixels = nullptr, int idivider = 0); bool did_texture_fail(); diff --git a/ui/viewercontainer.cpp b/ui/viewercontainer.cpp index 15d252f48..145cd49fc 100644 --- a/ui/viewercontainer.cpp +++ b/ui/viewercontainer.cpp @@ -28,6 +28,7 @@ ViewerContainer::ViewerContainer(QWidget *parent) : } ViewerContainer::~ViewerContainer() { + delete child; delete area; } diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 9b4abc5bd..29abe76f9 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -80,6 +80,7 @@ ViewerWidget::~ViewerWidget() { delete window; } renderer->cancel(); + delete renderer; } void ViewerWidget::delete_function() { @@ -212,15 +213,15 @@ void ViewerWidget::initializeGL() { void ViewerWidget::frame_update() { if (viewer->seq != nullptr) { - gizmos = nullptr; - drawn_gizmos = false; - force_quit = false; - bool render_audio = (viewer->playing || audio_rendering); // send context to other thread for drawing - doneCurrent(); - renderer->start_render(context(), viewer->seq); + if (waveform) { + update(); + } else { + doneCurrent(); + renderer->start_render(context(), viewer->seq); + } // render the audio compose_audio(viewer, viewer->seq, render_audio); @@ -248,7 +249,7 @@ void ViewerWidget::seek_from_click(int x) { EffectGizmo* ViewerWidget::get_gizmo_from_mouse(int x, int y) { if (gizmos != nullptr) { double multiplier = double(viewer->seq->width) / double(width()); - QPoint mouse_pos(qRound(x*multiplier), qRound(y*multiplier)); + QPoint mouse_pos(qRound(x*multiplier), qRound((height()-y)*multiplier)); int dot_size = 2 * qRound(GIZMO_DOT_SIZE * multiplier); int target_size = 2 * qRound(GIZMO_TARGET_SIZE * multiplier); for (int i=0;igizmo_count();i++) { @@ -277,8 +278,10 @@ EffectGizmo* ViewerWidget::get_gizmo_from_mouse(int x, int y) { } break; } - } + + qDebug() << mouse_pos.x() << gizmos->gizmo(0)->screen_pos[0].x(); + qDebug() << mouse_pos.y() << gizmos->gizmo(0)->screen_pos[0].y(); } return nullptr; } @@ -358,7 +361,28 @@ void ViewerWidget::mouseReleaseEvent(QMouseEvent *event) { dragging = false; } -void ViewerWidget::drawTitleSafeArea() { +void ViewerWidget::draw_waveform_func() { + QPainter p(this); + if (viewer->seq->using_workarea) { + int in_x = getScreenPointFromFrame(waveform_zoom, viewer->seq->workarea_in) - waveform_scroll; + int out_x = getScreenPointFromFrame(waveform_zoom, viewer->seq->workarea_out) - waveform_scroll; + + p.fillRect(QRect(in_x, 0, out_x - in_x, height()), QColor(255, 255, 255, 64)); + p.setPen(Qt::white); + p.drawLine(in_x, 0, in_x, height()); + p.drawLine(out_x, 0, out_x, height()); + } + QRect wr = rect(); + wr.setX(wr.x() - waveform_scroll); + + p.setPen(Qt::green); + draw_waveform(waveform_clip, waveform_ms, waveform_clip->timeline_out, &p, wr, waveform_scroll, width()+waveform_scroll, waveform_zoom); + p.setPen(Qt::red); + int playhead_x = getScreenPointFromFrame(waveform_zoom, viewer->seq->playhead) - waveform_scroll; + p.drawLine(playhead_x, 0, playhead_x, height()); +} + +void ViewerWidget::draw_title_safe_area() { double halfWidth = 0.5; double halfHeight = 0.5; double viewportAr = (double) width() / (double) height(); @@ -426,8 +450,71 @@ void ViewerWidget::drawTitleSafeArea() { glEnd(); } +void ViewerWidget::draw_gizmos() { + float color[4]; + glGetFloatv(GL_CURRENT_COLOR, color); + + float dot_size = GIZMO_DOT_SIZE / width() * viewer->seq->width; + float target_size = GIZMO_TARGET_SIZE / width() * viewer->seq->width; + + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, viewer->seq->width, 0, viewer->seq->height, -1, 10); + float gizmo_z = 0.0f; + for (int j=0;jgizmo_count();j++) { + EffectGizmo* g = gizmos->gizmo(j); + glColor4f(g->color.redF(), g->color.greenF(), g->color.blueF(), 1.0); + switch (g->get_type()) { + case GIZMO_TYPE_DOT: // draw dot + glBegin(GL_QUADS); + glVertex3f(g->screen_pos[0].x()-dot_size, g->screen_pos[0].y()-dot_size, gizmo_z); + glVertex3f(g->screen_pos[0].x()+dot_size, g->screen_pos[0].y()-dot_size, gizmo_z); + glVertex3f(g->screen_pos[0].x()+dot_size, g->screen_pos[0].y()+dot_size, gizmo_z); + glVertex3f(g->screen_pos[0].x()-dot_size, g->screen_pos[0].y()+dot_size, gizmo_z); + glEnd(); + break; + case GIZMO_TYPE_POLY: // draw lines + glBegin(GL_LINES); + for (int k=1;kget_point_count();k++) { + glVertex3f(g->screen_pos[k-1].x(), g->screen_pos[k-1].y(), gizmo_z); + glVertex3f(g->screen_pos[k].x(), g->screen_pos[k].y(), gizmo_z); + } + glVertex3f(g->screen_pos[g->get_point_count()-1].x(), g->screen_pos[g->get_point_count()-1].y(), gizmo_z); + glVertex3f(g->screen_pos[0].x(), g->screen_pos[0].y(), gizmo_z); + glEnd(); + break; + case GIZMO_TYPE_TARGET: // draw target + glBegin(GL_LINES); + glVertex3f(g->screen_pos[0].x()-target_size, g->screen_pos[0].y()-target_size, gizmo_z); + glVertex3f(g->screen_pos[0].x()+target_size, g->screen_pos[0].y()-target_size, gizmo_z); + + glVertex3f(g->screen_pos[0].x()+target_size, g->screen_pos[0].y()-target_size, gizmo_z); + glVertex3f(g->screen_pos[0].x()+target_size, g->screen_pos[0].y()+target_size, gizmo_z); + + glVertex3f(g->screen_pos[0].x()+target_size, g->screen_pos[0].y()+target_size, gizmo_z); + glVertex3f(g->screen_pos[0].x()-target_size, g->screen_pos[0].y()+target_size, gizmo_z); + + glVertex3f(g->screen_pos[0].x()-target_size, g->screen_pos[0].y()+target_size, gizmo_z); + glVertex3f(g->screen_pos[0].x()-target_size, g->screen_pos[0].y()-target_size, gizmo_z); + + glVertex3f(g->screen_pos[0].x()-target_size, g->screen_pos[0].y(), gizmo_z); + glVertex3f(g->screen_pos[0].x()+target_size, g->screen_pos[0].y(), gizmo_z); + + glVertex3f(g->screen_pos[0].x(), g->screen_pos[0].y()-target_size, gizmo_z); + glVertex3f(g->screen_pos[0].x(), g->screen_pos[0].y()+target_size, gizmo_z); + glEnd(); + break; + } + } + glPopMatrix(); + + glColor4f(color[0], color[1], color[2], color[3]); +} + void ViewerWidget::paintGL() { -// if (renderer->mutex.tryLock(10)) { + if (waveform) { + draw_waveform_func(); + } else { renderer->mutex.lock(); makeCurrent(); @@ -466,9 +553,13 @@ void ViewerWidget::paintGL() { glBindTexture(GL_TEXTURE_2D, 0); // draw title/action safe area - if (config.show_title_safe_area) { - drawTitleSafeArea(); + draw_title_safe_area(); + } + + gizmos = renderer->gizmos; + if (gizmos != nullptr) { + draw_gizmos(); } glDisable(GL_TEXTURE_2D); @@ -483,7 +574,7 @@ void ViewerWidget::paintGL() { doneCurrent(); renderer->start_render(context(), viewer->seq); } -// } + } // retry_timer.stop(); diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h index 3f7cb964b..980e88dec 100644 --- a/ui/viewerwidget.h +++ b/ui/viewerwidget.h @@ -41,8 +41,6 @@ public: double waveform_zoom; int waveform_scroll; - bool force_quit; - void frame_update(); RenderThread* get_renderer(); public slots: @@ -52,7 +50,11 @@ protected: void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); private: - void drawTitleSafeArea(); + void draw_waveform_func(); + void draw_title_safe_area(); + void draw_gizmos(); + EffectGizmo* get_gizmo_from_mouse(int x, int y); + void move_gizmos(QMouseEvent *event, bool done); bool dragging; void seek_from_click(int x); Effect* gizmos; @@ -61,9 +63,6 @@ private: int gizmo_x_mvmt; int gizmo_y_mvmt; EffectGizmo* selected_gizmo; - EffectGizmo* get_gizmo_from_mouse(int x, int y); - bool drawn_gizmos; - void move_gizmos(QMouseEvent *event, bool done); RenderThread* renderer; ViewerWindow* window; private slots: