diff --git a/io/loadthread.cpp b/io/loadthread.cpp index 957bb84aa..64d87ff9a 100644 --- a/io/loadthread.cpp +++ b/io/loadthread.cpp @@ -153,12 +153,12 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { if (type == LOAD_TYPE_VERSION) { int proj_version = stream.readElementText().toInt(); if (proj_version < MIN_SAVE_VERSION && proj_version > SAVE_VERSION) { - if (QMessageBox::warning( - mainWindow, - tr("Version Mismatch"), - tr("This project was saved in a different version of Olive and may not be fully compatible with this version. Would you like to attempt loading it anyway?"), - QMessageBox::Yes, - QMessageBox::No) == QMessageBox::No) { + if (QMessageBox::warning( + mainWindow, + tr("Version Mismatch"), + tr("This project was saved in a different version of Olive and may not be fully compatible with this version. Would you like to attempt loading it anyway?"), + QMessageBox::Yes, + QMessageBox::No) == QMessageBox::No) { show_err = false; return false; } @@ -444,11 +444,11 @@ bool LoadThread::load_worker(QFile& f, QXmlStreamReader& stream, int type) { if (!found) { correct_clip->linked.removeAt(j); j--; - if (QMessageBox::warning(mainWindow, - tr("Invalid Clip Link"), - tr("This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it?"), - QMessageBox::Yes, - QMessageBox::No) == QMessageBox::No) { + if (QMessageBox::warning(mainWindow, + tr("Invalid Clip Link"), + tr("This project contains an invalid clip link. It may be corrupt. Would you like to continue loading it?"), + QMessageBox::Yes, + QMessageBox::No) == QMessageBox::No) { delete s; return false; } @@ -601,7 +601,7 @@ void LoadThread::run() { xml_error = false; if (show_err) emit error(); } else if (stream.hasError()) { - error_str = tr("%1 - Line: %2 Col: %3").arg(stream.errorString(), QString::number(stream.lineNumber()), QString::number(stream.columnNumber())); + error_str = tr("%1 - Line: %2 Col: %3").arg(stream.errorString(), QString::number(stream.lineNumber()), QString::number(stream.columnNumber())); xml_error = true; emit error(); cont = false; @@ -641,15 +641,15 @@ void LoadThread::cancel() { void LoadThread::error_func() { if (xml_error) { qCritical() << "Error parsing XML." << error_str; - QMessageBox::critical(mainWindow, - tr("XML Parsing Error"), - tr("Couldn't load '%1'. %2").arg(project_url, error_str), - QMessageBox::Ok); + QMessageBox::critical(mainWindow, + tr("XML Parsing Error"), + tr("Couldn't load '%1'. %2").arg(project_url, error_str), + QMessageBox::Ok); } else { - QMessageBox::critical(mainWindow, - tr("Project Load Error"), - tr("Error loading project: %1").arg(error_str), - QMessageBox::Ok); + QMessageBox::critical(mainWindow, + tr("Project Load Error"), + tr("Error loading project: %1").arg(error_str), + QMessageBox::Ok); } } diff --git a/olive.pro b/olive.pro index 698daa18d..6cc52430a 100644 --- a/olive.pro +++ b/olive.pro @@ -126,7 +126,8 @@ SOURCES += \ dialogs/texteditdialog.cpp \ dialogs/debugdialog.cpp \ ui/renderthread.cpp \ - ui/renderfunctions.cpp + ui/renderfunctions.cpp \ + ui/viewerwindow.cpp HEADERS += \ mainwindow.h \ @@ -220,7 +221,8 @@ HEADERS += \ dialogs/texteditdialog.h \ dialogs/debugdialog.h \ ui/renderthread.h \ - ui/renderfunctions.h + ui/renderfunctions.h \ + ui/viewerwindow.h FORMS += diff --git a/panels/project.cpp b/panels/project.cpp index b12ee265d..035d58a0b 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -913,7 +913,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, } // save_folder(stream, item, type, set_ids_only); } else { - int folder = (m->parentItem() != nullptr) ? m->parentItem()->temp_id : 0; + int folder = m->parentItem()->temp_id; if (type == MEDIA_TYPE_FOOTAGE) { Footage* f = m->to_footage(); f->save_id = media_id; diff --git a/panels/viewer.cpp b/panels/viewer.cpp index 7969e8445..c1bdfab2c 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -44,7 +44,7 @@ Viewer::Viewer(QWidget *parent) : seq(nullptr), created_sequence(false), cue_recording_internal(false), - panel_name(tr("Viewer: ")), + panel_name(tr("Viewer: ")), minimum_zoom(1.0) { setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -107,7 +107,9 @@ void Viewer::reset_all_audio() { for (int i=0;iclips.size();i++) { Clip* c = seq->clips.at(i); - if (c != nullptr) c->reset_audio(); + if (c != nullptr) { + c->reset_audio(); + } } } clear_audio_ibuffer(); @@ -251,9 +253,9 @@ void Viewer::seek(long p) { update_fx = true; } } - update_parents(update_fx); reset_all_audio(); audio_scrub = true; + update_parents(update_fx); } void Viewer::go_to_start() { @@ -439,7 +441,7 @@ void Viewer::resizeEvent(QResizeEvent *) { void Viewer::update_viewer() { update_header_zoom(); - viewer_widget->update(); + viewer_widget->frame_update(); if (seq != nullptr) update_playhead_timecode(seq->playhead); update_end_timecode(); } @@ -675,7 +677,7 @@ void Viewer::set_media(Media* m) { viewer_widget->waveform = true; viewer_widget->waveform_clip = c; viewer_widget->waveform_ms = &audio_stream; - viewer_widget->update(); + viewer_widget->frame_update(); } } else { seq->audio_frequency = 48000; @@ -785,12 +787,12 @@ void Viewer::set_sequence(bool main, Sequence *s) { update_playhead_timecode(0); update_end_timecode(); - setWindowTitle(panel_name + tr("(none)")); + setWindowTitle(panel_name + tr("(none)")); } update_header_zoom(); - viewer_widget->update(); + viewer_widget->frame_update(); update(); } diff --git a/playback/audio.cpp b/playback/audio.cpp index 915c42f8e..8655ab12b 100644 --- a/playback/audio.cpp +++ b/playback/audio.cpp @@ -102,8 +102,10 @@ void stop_audio() { void clear_audio_ibuffer() { if (audio_thread != nullptr) audio_thread->lock.lock(); + audio_write_lock.lock(); memset(audio_ibuffer, 0, audio_ibuffer_size); audio_ibuffer_read = 0; + audio_write_lock.unlock(); if (audio_thread != nullptr) audio_thread->lock.unlock(); } @@ -292,7 +294,7 @@ bool start_recording() { return false; } - QString audio_path = project_url + " " + QCoreApplication::translate("Audio", "Audio"); + QString audio_path = project_url + " " + QCoreApplication::translate("Audio", "Audio"); QDir audio_dir(audio_path); if (!audio_dir.exists() && !audio_dir.mkpath(".")) { qCritical() << "Failed to create audio directory"; @@ -303,7 +305,7 @@ bool start_recording() { int file_number = 0; do { file_number++; - audio_filename = audio_path + "/" + QCoreApplication::translate("Audio", "Recording") + " " + QString::number(file_number) + ".wav"; + audio_filename = audio_path + "/" + QCoreApplication::translate("Audio", "Recording") + " " + QString::number(file_number) + ".wav"; } while (QFile(audio_filename).exists()); output_recording.setFileName(audio_filename); diff --git a/playback/cacher.cpp b/playback/cacher.cpp index b6df93249..3066402e1 100644 --- a/playback/cacher.cpp +++ b/playback/cacher.cpp @@ -376,11 +376,13 @@ void cache_audio_worker(Clip* c, bool scrubbing, QVector& nests) { qint16 new_sample = static_cast((frame->data[0][c->frame_sample_index+1] & 0xFF) << 8 | (frame->data[0][c->frame_sample_index] & 0xFF)); qint16 mixed_sample = mix_audio_sample(old_sample, new_sample); - audio_ibuffer[upper_byte_index] = static_cast((mixed_sample >> 8) & 0xFF); - audio_ibuffer[lower_byte_index] = static_cast(mixed_sample & 0xFF); + audio_ibuffer[upper_byte_index] = quint8((mixed_sample >> 8) & 0xFF); + audio_ibuffer[lower_byte_index] = quint8(mixed_sample & 0xFF); c->audio_buffer_write+=2; c->frame_sample_index+=2; + + if (c->audio_reset) break; } #ifdef AUDIOWARNINGS @@ -389,6 +391,8 @@ void cache_audio_worker(Clip* c, bool scrubbing, QVector& nests) { audio_write_lock.unlock(); + if (c->audio_reset) return; + if (scrubbing) { if (audio_thread != nullptr) audio_thread->notifyReceiver(); } @@ -558,7 +562,9 @@ void reset_cache(Clip* c, long target_frame) { } else { if (c->stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { // clear current queue + c->queue_lock.lock(); c->queue_clear(); + c->queue_lock.unlock(); // seeks to nearest keyframe (target_frame represents internal clip frame) int64_t target_ts = seconds_to_timestamp(c, playhead_to_clip_seconds(c, target_frame)); diff --git a/playback/playback.cpp b/playback/playback.cpp index e27353687..edd55a98b 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -158,8 +158,10 @@ void get_clip_frame(Clip* c, long playhead) { #endif closest_frame = i; break; - } else if (c->queue.at(i)->pts > c->queue.at(closest_frame)->pts && c->queue.at(i)->pts < target_pts) { - closest_frame = i; + } else { + if (c->queue.at(i)->pts > c->queue.at(closest_frame)->pts && c->queue.at(i)->pts < target_pts) { + closest_frame = i; + } } } @@ -247,7 +249,7 @@ void get_clip_frame(Clip* c, long playhead) { if (target_frame == nullptr || reset) { // reset cache texture_failed = true; - qInfo() << "Frame queue couldn't keep up - either the user seeked or the system is overloaded (queue size:" << c->queue.size() << ")"; +// qInfo() << "Frame queue couldn't keep up - either the user seeked or the system is overloaded (queue size:" << c->queue.size() << ")"; } if (target_frame != nullptr) { diff --git a/project/projectmodel.cpp b/project/projectmodel.cpp index acec09122..564498214 100644 --- a/project/projectmodel.cpp +++ b/project/projectmodel.cpp @@ -7,14 +7,19 @@ #include "debug.h" ProjectModel::ProjectModel(QObject *parent) : QAbstractItemModel(parent), root_item(nullptr) { - root_item = new Media(0); - root_item->root = true; + make_root(); } ProjectModel::~ProjectModel() { destroy_root(); } +void ProjectModel::make_root() { + root_item = new Media(nullptr); + root_item->temp_id = 0; + root_item->root = true; +} + void ProjectModel::destroy_root() { if (panel_sequence_viewer != nullptr) panel_sequence_viewer->viewer_widget->delete_function(); if (panel_footage_viewer != nullptr) panel_footage_viewer->viewer_widget->delete_function(); @@ -27,8 +32,7 @@ void ProjectModel::destroy_root() { void ProjectModel::clear() { beginResetModel(); destroy_root(); - root_item = new Media(0); - root_item->root = true; + make_root(); endResetModel(); } diff --git a/project/projectmodel.h b/project/projectmodel.h index 03ea9eadb..349080b7a 100644 --- a/project/projectmodel.h +++ b/project/projectmodel.h @@ -9,9 +9,10 @@ class ProjectModel : public QAbstractItemModel { Q_OBJECT public: - ProjectModel(QObject* parent = 0); + ProjectModel(QObject* parent = nullptr); ~ProjectModel() override; + void make_root(); void destroy_root(); void clear(); Media* get_root(); diff --git a/ui/renderfunctions.cpp b/ui/renderfunctions.cpp index b99200375..2971f3703 100644 --- a/ui/renderfunctions.cpp +++ b/ui/renderfunctions.cpp @@ -425,7 +425,7 @@ GLuint compose_sequence(Viewer* viewer, glBindTexture(GL_TEXTURE_2D, 0); // unbind texture // TODO restore this function - /*if (gizmos != nullptr && !drawn_gizmos && nests.isEmpty()) { + /*if ((*gizmos) != nullptr && !drawn_gizmos && nests.isEmpty()) { (*gizmos)->gizmo_draw(timecode, coords); // set correct gizmo coords (*gizmos)->gizmo_world_to_screen(); diff --git a/ui/renderthread.cpp b/ui/renderthread.cpp index 460f8be99..81304aa51 100644 --- a/ui/renderthread.cpp +++ b/ui/renderthread.cpp @@ -7,12 +7,16 @@ #include "ui/renderfunctions.h" #include "playback/playback.h" +#include "project/sequence.h" RenderThread::RenderThread() : share_ctx(nullptr), ctx(nullptr), frameBuffer(0), - texColorBuffer(0) + texColorBuffer(0), + tex_width(-1), + tex_height(-1), + queued(false) { surface.create(); } @@ -27,7 +31,10 @@ void RenderThread::run() { bool running = true; while (running) { - waitCond.wait(&mutex); + if (!queued) { + waitCond.wait(&mutex); + } + queued = false; if (share_ctx != nullptr) { if (ctx == nullptr) { @@ -48,12 +55,20 @@ void RenderThread::run() { ctx->functions()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer); // gen texture - if (texColorBuffer == 0) { + if (texColorBuffer == 0 || tex_width != seq->width || tex_height != seq->height) {\ + if (texColorBuffer > 0) { + ctx->functions()->glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0 + ); + glDeleteTextures(1, &texColorBuffer); + } glGenTextures(1, &texColorBuffer); glBindTexture(GL_TEXTURE_2D, texColorBuffer); glTexImage2D( - GL_TEXTURE_2D, 0, GL_RGB, 1920, 1080, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr + GL_TEXTURE_2D, 0, GL_RGB, seq->width, seq->height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr ); + tex_width = seq->width; + tex_height = seq->height; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); ctx->functions()->glFramebufferTexture2D( @@ -70,12 +85,15 @@ void RenderThread::run() { // release ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, 0); + + emit ready(); } } } if (ctx != nullptr) { - if (frameBuffer != 0) ctx->functions()->glDeleteFramebuffers(1, &frameBuffer); + if (texColorBuffer > 0) glDeleteTextures(1, &texColorBuffer); + if (frameBuffer > 0) ctx->functions()->glDeleteFramebuffers(1, &frameBuffer); ctx->doneCurrent(); delete ctx; } @@ -110,5 +128,6 @@ void RenderThread::paint() { void RenderThread::start_render(QOpenGLContext *share, Sequence *s, int idivider) { share_ctx = share; seq = s; + queued = true; waitCond.wakeAll(); } diff --git a/ui/renderthread.h b/ui/renderthread.h index 98414937c..e3e1d1def 100644 --- a/ui/renderthread.h +++ b/ui/renderthread.h @@ -11,6 +11,7 @@ struct Sequence; class RenderThread : public QThread { + Q_OBJECT public: RenderThread(); ~RenderThread(); @@ -20,6 +21,8 @@ public: GLuint texColorBuffer; void paint(); void start_render(QOpenGLContext* share, Sequence* s, int idivider = 0); +signals: + void ready(); private: QWaitCondition waitCond; QOffscreenSurface surface; @@ -27,6 +30,9 @@ private: QOpenGLContext* ctx; Sequence* seq; int divider; + int tex_width; + int tex_height; + bool queued; }; #endif // RENDERTHREAD_H diff --git a/ui/viewerwidget.cpp b/ui/viewerwidget.cpp index 5090ab1a7..ae5065696 100644 --- a/ui/viewerwidget.cpp +++ b/ui/viewerwidget.cpp @@ -23,6 +23,8 @@ #include "ui/timelinewidget.h" #include "ui/renderfunctions.h" #include "ui/renderthread.h" +#include "Ui/viewerwindow.h" +#include "mainwindow.h" #include #include @@ -39,6 +41,8 @@ #include #include #include +#include +#include extern "C" { #include @@ -53,7 +57,8 @@ ViewerWidget::ViewerWidget(QWidget *parent) : dragging(false), gizmos(nullptr), selected_gizmo(nullptr), - just_repaint(false) + just_repaint(false), + window(nullptr) { setMouseTracking(true); setFocusPolicy(Qt::ClickFocus); @@ -62,15 +67,19 @@ ViewerWidget::ViewerWidget(QWidget *parent) : format.setDepthBufferSize(24); setFormat(format); - // error handler - retries after 50ms if we couldn't get the entire image - retry_timer.setInterval(50); - connect(&retry_timer, SIGNAL(timeout()), this, SLOT(retry())); - setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_context_menu())); renderer = new RenderThread(); renderer->start(QThread::HighPriority); + connect(renderer, SIGNAL(ready()), this, SLOT(queue_repaint())); +} + +ViewerWidget::~ViewerWidget() { + if (window != nullptr) { + window->close(); + delete window; + } } void ViewerWidget::delete_function() { @@ -95,8 +104,18 @@ void ViewerWidget::show_context_menu() { QAction* save_frame_as_image = menu.addAction(tr("Save Frame as Image...")); connect(save_frame_as_image, SIGNAL(triggered(bool)), this, SLOT(save_frame())); - QAction* show_fullscreen_action = menu.addAction(tr("Show Fullscreen")); - connect(show_fullscreen_action, SIGNAL(triggered()), this, SLOT(show_fullscreen())); + /*QAction* show_fullscreen_action = menu.addAction(tr("Show Fullscreen")); + connect(show_fullscreen_action, SIGNAL(triggered()), this, SLOT(show_fullscreen()));*/ + QMenu* fullscreen_menu = menu.addMenu(tr("Show Fullscreen")); + QList screens = QGuiApplication::screens(); + for (int i=0;iaddAction(tr("Screen %1: %2x%3").arg( + QString::number(i), + QString::number(screens.at(i)->size().width()), + QString::number(screens.at(i)->size().height()))); + screen_action->setData(i); + } + connect(fullscreen_menu, SIGNAL(triggered(QAction*)), this, SLOT(fullscreen_menu_action(QAction*))); QMenu zoom_menu(tr("Zoom")); QAction* fit_zoom = zoom_menu.addAction(tr("Fit")); @@ -153,8 +172,20 @@ void ViewerWidget::save_frame() { } } -void ViewerWidget::show_fullscreen() { - showFullScreen(); +void ViewerWidget::queue_repaint() { + just_repaint = true; + update(); +} + +void ViewerWidget::fullscreen_menu_action(QAction *action) { + if (window == nullptr) { + QMessageBox::critical(this, "Error", "Failed to create viewer window"); + } else { + QScreen* selected_screen = QGuiApplication::screens().at(action->data().toInt()); + window->showFullScreen(); + window->setGeometry(selected_screen->geometry()); +// window->show(); + } } void ViewerWidget::set_fit_zoom() { @@ -193,19 +224,41 @@ void ViewerWidget::initializeGL() { connect(context(), SIGNAL(aboutToBeDestroyed()), this, SLOT(delete_function()), Qt::DirectConnection); - retry_timer.start(); + if (window != nullptr) { + delete window; + } + window = new ViewerWindow(context()); + +// retry_timer.start(); +} + +void ViewerWidget::frame_update() { + if (viewer->seq != nullptr) { + gizmos = nullptr; + drawn_gizmos = false; + force_quit = false; + + bool render_audio = (viewer->playing || rendering); + + // send context to other thread for drawing + doneCurrent(); + renderer->start_render(context(), viewer->seq); + + // render the audio + QVector nests; + compose_sequence(viewer, context(), viewer->seq, nests, false, render_audio, &gizmos); + } } //void ViewerWidget::resizeGL(int w, int h) //{ //} -void ViewerWidget::paintEvent(QPaintEvent *e) { - if (!rendering && context()->thread() == this->thread()) { - makeCurrent(); +/*void ViewerWidget::paintEvent(QPaintEvent *e) { + if (!rendering) { QOpenGLWidget::paintEvent(e); } -} +}*/ void ViewerWidget::seek_from_click(int x) { viewer->seek(getFrameFromScreenPoint(waveform_zoom, x+waveform_scroll)); @@ -393,8 +446,51 @@ void ViewerWidget::drawTitleSafeArea() { } void ViewerWidget::paintGL() { - retry_timer.stop(); + if (renderer->mutex.tryLock(10)) { + makeCurrent(); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, renderer->texColorBuffer); + + glLoadIdentity(); + glOrtho(0, 1, 1, 0, -1, 1); + + glBegin(GL_QUADS); + + glVertex2f(0, 0); + glTexCoord2f(0, 0); + glVertex2f(0, 1); + glTexCoord2f(1, 0); + glVertex2f(1, 1); + glTexCoord2f(1, 1); + glVertex2f(1, 0); + glTexCoord2f(0, 1); + + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); + + glDisable(GL_TEXTURE_2D); + + if (window != nullptr && window->isVisible()) { + window->set_texture(renderer->texColorBuffer, double(viewer->seq->width)/double(viewer->seq->height)); + } + + renderer->mutex.unlock(); + + if (texture_failed) { + doneCurrent(); + renderer->start_render(context(), viewer->seq); + } + } + +// retry_timer.stop(); + + /* if (viewer->seq != nullptr) { gizmos = nullptr; drawn_gizmos = false; @@ -410,53 +506,57 @@ void ViewerWidget::paintGL() { // render the audio QVector nests; compose_sequence(viewer, context(), viewer->seq, nests, false, render_audio, &gizmos); - } - - // try to draw the texture from the other thread if we got it - if (renderer->mutex.tryLock(10)) { - makeCurrent(); - - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - - glEnable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, renderer->texColorBuffer); - - glLoadIdentity(); - glOrtho(0, 1, 1, 0, -1, 1); - - glBegin(GL_QUADS); - - glVertex2f(0, 0); - glTexCoord2f(0, 0); - glVertex2f(0, 1); - glTexCoord2f(1, 0); - glVertex2f(1, 1); - glTexCoord2f(1, 1); - glVertex2f(1, 0); - glTexCoord2f(0, 1); - - glEnd(); - - glBindTexture(GL_TEXTURE_2D, 0); - - glDisable(GL_TEXTURE_2D); - - renderer->mutex.unlock(); - - if (texture_failed) { - qDebug() << "texture failed, retry called"; - retry_timer.start(); - } } else { - qDebug() << "renderer failed, retry called"; - retry_timer.start(); - just_repaint = true; - } - } + // try to draw the texture from the other thread if we got it +// if (renderer->mutex.tryLock(10)) { + makeCurrent(); - just_repaint = false; + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, renderer->texColorBuffer); + + glLoadIdentity(); + glOrtho(0, 1, 1, 0, -1, 1); + + glBegin(GL_QUADS); + + glVertex2f(0, 0); + glTexCoord2f(0, 0); + glVertex2f(0, 1); + glTexCoord2f(1, 0); + glVertex2f(1, 1); + glTexCoord2f(1, 1); + glVertex2f(1, 0); + glTexCoord2f(0, 1); + + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); + + glDisable(GL_TEXTURE_2D); + + if (window != nullptr && window->isVisible()) { + window->set_texture(renderer->texColorBuffer, double(viewer->seq->width)/double(viewer->seq->height)); + } + +// renderer->mutex.unlock(); + +// if (texture_failed) { +// qDebug() << "texture failed, retry called"; +// retry_timer.start(); +// } +// } else { +// qDebug() << "renderer failed, retry called"; +// retry_timer.start(); +// just_repaint = true; +// } + } + + just_repaint = false; + }*/ /*drawn_gizmos = false; diff --git a/ui/viewerwidget.h b/ui/viewerwidget.h index ce6a5f555..dd764101b 100644 --- a/ui/viewerwidget.h +++ b/ui/viewerwidget.h @@ -19,12 +19,14 @@ class EffectGizmo; class ViewerContainer; struct GLTextureCoords; class RenderThread; +class ViewerWindow; class ViewerWidget : public QOpenGLWidget, QOpenGLFunctions { Q_OBJECT public: ViewerWidget(QWidget *parent = 0); + ~ViewerWidget(); void paintGL(); void initializeGL(); @@ -40,23 +42,21 @@ public: int waveform_scroll; bool force_quit; + + void frame_update(); public slots: void delete_function(); void set_waveform_scroll(int s); protected: - void paintEvent(QPaintEvent *e); +// void paintEvent(QPaintEvent *e); // void resizeGL(int w, int h); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); private: - QTimer retry_timer; void drawTitleSafeArea(); bool dragging; void seek_from_click(int x); -// GLuint compose_sequence(QVector &nests, bool video, bool render_audio); -// GLuint draw_clip(QOpenGLFramebufferObject *clip, GLuint texture, bool clear); -// void process_effect(Clip* c, Effect* e, double timecode, GLTextureCoords& coords, GLuint& composite_texture, bool& fbo_switcher, int data); Effect* gizmos; int drag_start_x; int drag_start_y; @@ -67,13 +67,14 @@ private: bool drawn_gizmos; void move_gizmos(QMouseEvent *event, bool done); RenderThread* renderer; + ViewerWindow* window; bool just_repaint; private slots: void retry(); void show_context_menu(); void save_frame(); - void show_fullscreen(); - + void queue_repaint(); + void fullscreen_menu_action(QAction* action); void set_fit_zoom(); void set_custom_zoom(); void set_menu_zoom(QAction *action); diff --git a/ui/viewerwindow.cpp b/ui/viewerwindow.cpp new file mode 100644 index 000000000..3de4ac54e --- /dev/null +++ b/ui/viewerwindow.cpp @@ -0,0 +1,62 @@ +#include "viewerwindow.h" + +ViewerWindow::ViewerWindow(QOpenGLContext *share) : + QOpenGLWindow(share), + texture(0) +{} + +void ViewerWindow::set_texture(GLuint t, double iar) { + texture = t; + ar = iar; + update(); +} + +void ViewerWindow::paintGL() { + if (texture > 0) { + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, texture); + + glLoadIdentity(); + glOrtho(0, 1, 1, 0, -1, 1); + + glBegin(GL_QUADS); + + double top = 0; + double left = 0; + double right = 1; + double bottom = 1; + + double widget_ar = double(width()) / double(height()); + + if (widget_ar > ar) { + /*widget_width = widget_height * aspect_ratio; + widget_x = (width() / 2) - (widget_width / 2);*/ + double width = 1.0 * ar / widget_ar; + left = (1.0 - width)*0.5; + right = left + width; + } else { + double height = 1.0 / ar * widget_ar; + top = (1.0 - height)*0.5; + bottom = top + height; + } + + glVertex2d(left, top); + glTexCoord2d(0, 0); + glVertex2d(left, bottom); + glTexCoord2d(1, 0); + glVertex2d(right, bottom); + glTexCoord2d(1, 1); + glVertex2d(right, top); + glTexCoord2d(0, 1); + + glEnd(); + + glBindTexture(GL_TEXTURE_2D, 0); + + glDisable(GL_TEXTURE_2D); + } +} diff --git a/ui/viewerwindow.h b/ui/viewerwindow.h new file mode 100644 index 000000000..7444222cf --- /dev/null +++ b/ui/viewerwindow.h @@ -0,0 +1,17 @@ +#ifndef VIEWERWINDOW_H +#define VIEWERWINDOW_H + +#include + +class ViewerWindow : public QOpenGLWindow { + Q_OBJECT +public: + ViewerWindow(QOpenGLContext* share); + void set_texture(GLuint t, double iar); +private: + void paintGL(); + GLuint texture; + double ar; +}; + +#endif // VIEWERWINDOW_H