diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.cpp b/app/dialog/preferences/tabs/preferencesaudiotab.cpp index af70cb1d2..dfe3536a7 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.cpp +++ b/app/dialog/preferences/tabs/preferencesaudiotab.cpp @@ -22,7 +22,6 @@ #include #include -#include #include "audio/audiomanager.h" #include "config/config.h" @@ -80,14 +79,14 @@ PreferencesAudioTab::PreferencesAudioTab() row++; - QPushButton* refresh_devices = new QPushButton(tr("Refresh Devices")); - audio_tab_layout->addWidget(refresh_devices, row, 1); + refresh_devices_btn_ = new QPushButton(tr("Refresh Devices")); + audio_tab_layout->addWidget(refresh_devices_btn_, row, 1); row++; RetrieveDeviceLists(); - connect(refresh_devices, &QPushButton::clicked, this, &PreferencesAudioTab::RefreshDevices); + connect(refresh_devices_btn_, &QPushButton::clicked, this, &PreferencesAudioTab::RefreshDevices); connect(AudioManager::instance(), &AudioManager::OutputListReady, this, &PreferencesAudioTab::RetrieveOutputList); connect(AudioManager::instance(), &AudioManager::InputListReady, this, &PreferencesAudioTab::RetrieveInputList); } @@ -151,6 +150,8 @@ void PreferencesAudioTab::RetrieveOutputList() AudioManager::instance()->IsRefreshingOutputs(), AudioManager::instance()->ListOutputDevices(), Config::Current()["AudioOutput"].toString()); + + UpdateRefreshButtonEnabled(); } void PreferencesAudioTab::RetrieveInputList() @@ -159,6 +160,8 @@ void PreferencesAudioTab::RetrieveInputList() AudioManager::instance()->IsRefreshingInputs(), AudioManager::instance()->ListInputDevices(), Config::Current()["AudioInput"].toString()); + + UpdateRefreshButtonEnabled(); } void PreferencesAudioTab::RetrieveDeviceLists() @@ -167,17 +170,22 @@ void PreferencesAudioTab::RetrieveDeviceLists() RetrieveInputList(); } +void PreferencesAudioTab::UpdateRefreshButtonEnabled() +{ + refresh_devices_btn_->setEnabled(audio_output_devices_->isEnabled() + && audio_input_devices_->isEnabled()); +} + void PreferencesAudioTab::PopulateComboBox(QComboBox *cb, bool still_refreshing, const QList &list, const QString& preferred) { cb->clear(); - cb->setEnabled(still_refreshing); + cb->setEnabled(!still_refreshing); if (still_refreshing) { cb->addItem(tr("Please wait...")); } else { bool found_preferred_device = false; - cb->setEnabled(true); // Add null default item cb->addItem(tr("Default"), QVariant()); diff --git a/app/dialog/preferences/tabs/preferencesaudiotab.h b/app/dialog/preferences/tabs/preferencesaudiotab.h index f91445774..dcf9252b7 100644 --- a/app/dialog/preferences/tabs/preferencesaudiotab.h +++ b/app/dialog/preferences/tabs/preferencesaudiotab.h @@ -23,6 +23,7 @@ #include #include +#include #include "preferencestab.h" @@ -57,6 +58,11 @@ private: */ QComboBox* recording_combobox_; + /** + * @brief Button that triggers a refresh of the available audio devices + */ + QPushButton* refresh_devices_btn_; + private slots: void RefreshDevices(); @@ -67,6 +73,8 @@ private slots: private: void RetrieveDeviceLists(); + void UpdateRefreshButtonEnabled(); + static void PopulateComboBox(QComboBox* cb, bool still_refreshing, const QList& list, const QString &preferred); }; diff --git a/app/main.cpp b/app/main.cpp index 859ed0b76..8713f4d96 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -50,8 +50,8 @@ int main(int argc, char *argv[]) { format.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(format); - // Try to share OpenGL contexts - QApplication::setAttribute(Qt::AA_ShareOpenGLContexts); + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); // Create application instance QApplication a(argc, argv); diff --git a/app/panel/panelmanager.cpp b/app/panel/panelmanager.cpp index f85e6824f..53903f81e 100644 --- a/app/panel/panelmanager.cpp +++ b/app/panel/panelmanager.cpp @@ -35,10 +35,10 @@ PanelManager::PanelManager(QObject *parent) : void PanelManager::DeleteAllPanels() { - foreach (PanelWidget* panel, focus_history_) { - delete panel; - } + // Prevent any confusion regarding focus history by clearing it first + QList copy = focus_history_; focus_history_.clear(); + qDeleteAll(copy); } const QList &PanelManager::panels() diff --git a/app/panel/panelmanager.h b/app/panel/panelmanager.h index 7acba73e3..caa7bae07 100644 --- a/app/panel/panelmanager.h +++ b/app/panel/panelmanager.h @@ -175,14 +175,26 @@ T *PanelManager::CreatePanel(QWidget *parent) { T* panel = new T(parent); - panel->SetMovementLocked(locked_); - - // Connect destroy signal so we can remove it from focus history - connect(panel, &PanelWidget::destroyed, this, &PanelManager::PanelDestroyed); - // Add panel to the bottom of the focus history focus_history_.append(panel); + panel->SetMovementLocked(locked_); + + // Sane default for panel size + panel->resize(parent->size() / 3); + + // We're about to center the panel relative to the parent (usually the main window), but for some + // reason this requires the panel to be shown first. + panel->show(); + + // Center the panel relative to the parent + QPoint parent_center = panel->mapFromGlobal(parent->mapToGlobal(parent->rect().center())); + QPoint panel_center = panel->rect().center(); + panel->move(parent_center - panel_center); + + // Connect destroy signal so we can remove it from focus history + connect(panel, &PanelWidget::destroyed, this, &PanelManager::PanelDestroyed, Qt::DirectConnection); + return panel; } diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index bdbb8e8e0..2544c7748 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -94,9 +94,11 @@ void ParamPanel::CreateCurvePanel(NodeInput *input) panel->SetInput(input); panel->SetTimebase(view->timebase()); panel->SetTimestamp(view->GetTimestamp()); + panel->SetTimeTarget(view->GetTimeTarget()); connect(view, &NodeParamView::TimebaseChanged, panel, &CurvePanel::SetTimebase); connect(view, &NodeParamView::TimeChanged, panel, &CurvePanel::SetTimestamp); + connect(view, &NodeParamView::TimeTargetChanged, panel, &CurvePanel::SetTimeTarget); connect(panel, &CurvePanel::TimeChanged, view, &NodeParamView::SetTimestamp); connect(panel, &CurvePanel::TimeChanged, view, &NodeParamView::TimeChanged); connect(panel, &CurvePanel::CloseRequested, this, &ParamPanel::ClosingCurvePanel); diff --git a/app/panel/scope/scope.cpp b/app/panel/scope/scope.cpp index 222fcec64..5daa7e9e0 100644 --- a/app/panel/scope/scope.cpp +++ b/app/panel/scope/scope.cpp @@ -84,19 +84,10 @@ QString ScopePanel::TypeToName(ScopePanel::Type t) return QString(); } -void ScopePanel::SetDisplayReferredTexture(OpenGLTexture *texture) -{ - Q_UNUSED(texture) -} - void ScopePanel::SetReferenceBuffer(Frame *frame) { histogram_->SetBuffer(frame); -} - -void ScopePanel::SetReferenceTexture(OpenGLTexture *texture) -{ - waveform_view_->SetTexture(texture); + waveform_view_->SetBuffer(frame); } void ScopePanel::SetColorManager(ColorManager *manager) diff --git a/app/panel/scope/scope.h b/app/panel/scope/scope.h index f44e37aa6..3e771af69 100644 --- a/app/panel/scope/scope.h +++ b/app/panel/scope/scope.h @@ -50,12 +50,8 @@ public: static QString TypeToName(Type t); public slots: - void SetDisplayReferredTexture(OpenGLTexture* texture); - void SetReferenceBuffer(Frame* frame); - void SetReferenceTexture(OpenGLTexture* texture); - void SetColorManager(ColorManager* manager); protected: diff --git a/app/panel/viewer/viewerbase.cpp b/app/panel/viewer/viewerbase.cpp index a8d4d55b8..3cab17f98 100644 --- a/app/panel/viewer/viewerbase.cpp +++ b/app/panel/viewer/viewerbase.cpp @@ -25,8 +25,7 @@ OLIVE_NAMESPACE_ENTER ViewerPanelBase::ViewerPanelBase(const QString& object_name, QWidget *parent) : - TimeBasedPanel(object_name, parent), - scope_panel_count_(0) + TimeBasedPanel(object_name, parent) { } @@ -98,33 +97,13 @@ void ViewerPanelBase::CreateScopePanel(ScopePanel::Type type) p->SetType(type); - // If the scope closes, reduce the count (we do this because if no scopes are open, we can optimize the viewer slightly) - connect(p, &ScopePanel::CloseRequested, this, &ViewerPanelBase::ScopePanelClosed); - // Connect viewer widget texture drawing to scope panel - connect(vw, &ViewerWidget::DrewManagedTexture, p, &ScopePanel::SetDisplayReferredTexture); connect(vw, &ViewerWidget::LoadedBuffer, p, &ScopePanel::SetReferenceBuffer); - connect(vw, &ViewerWidget::LoadedTexture, p, &ScopePanel::SetReferenceTexture); connect(vw, &ViewerWidget::ColorManagerChanged, p, &ScopePanel::SetColorManager); p->SetColorManager(vw->color_manager()); - if (!scope_panel_count_) { - vw->SetEmitDrewManagedTextureEnabled(true); - } - - scope_panel_count_++; - vw->ForceUpdate(); } -void ViewerPanelBase::ScopePanelClosed() -{ - scope_panel_count_--; - - if (!scope_panel_count_) { - static_cast(GetTimeBasedWidget())->SetEmitDrewManagedTextureEnabled(false); - } -} - OLIVE_NAMESPACE_EXIT diff --git a/app/panel/viewer/viewerbase.h b/app/panel/viewer/viewerbase.h index 7d551141d..a0acd2d29 100644 --- a/app/panel/viewer/viewerbase.h +++ b/app/panel/viewer/viewerbase.h @@ -59,12 +59,6 @@ public: protected: void CreateScopePanel(ScopePanel::Type type); -private: - int scope_panel_count_; - -private slots: - void ScopePanelClosed(); - }; OLIVE_NAMESPACE_EXIT diff --git a/app/render/backend/opengl/openglproxy.cpp b/app/render/backend/opengl/openglproxy.cpp index d1f4f7ddd..194ac6dc4 100644 --- a/app/render/backend/opengl/openglproxy.cpp +++ b/app/render/backend/opengl/openglproxy.cpp @@ -132,7 +132,7 @@ void OpenGLProxy::FrameToValue(FramePtr frame, StreamPtr stream, NodeValueTable* VideoRenderingParams footage_params(frame->width(), frame->height(), frame->format()); - footage_tex_ref = texture_cache_.Get(ctx_, footage_params, frame->data(), frame->linesize_pixels()); + footage_tex_ref = texture_cache_.Get(ctx_, footage_params, frame); if (ocio_method == ColorManager::kOCIOFast) { if (!color_processor->IsEnabled()) { diff --git a/app/render/backend/opengl/opengltexture.cpp b/app/render/backend/opengl/opengltexture.cpp index c0c1621ea..d5013c10f 100644 --- a/app/render/backend/opengl/opengltexture.cpp +++ b/app/render/backend/opengl/opengltexture.cpp @@ -74,6 +74,11 @@ void OpenGLTexture::Create(QOpenGLContext *ctx, int width, int height, const Pix } void OpenGLTexture::Create(QOpenGLContext *ctx, FramePtr frame) +{ + Create(ctx, frame.get()); +} + +void OpenGLTexture::Create(QOpenGLContext *ctx, Frame *frame) { Create(ctx, frame->width(), frame->height(), frame->format(), frame->data(), frame->linesize_pixels()); } @@ -120,6 +125,16 @@ const GLuint &OpenGLTexture::texture() const return texture_; } +void OpenGLTexture::Upload(FramePtr frame) +{ + Upload(frame.get()); +} + +void OpenGLTexture::Upload(Frame *frame) +{ + Upload(frame->data(), frame->linesize_pixels()); +} + void OpenGLTexture::Upload(const void *data, int linesize) { if (!IsCreated()) { diff --git a/app/render/backend/opengl/opengltexture.h b/app/render/backend/opengl/opengltexture.h index 941e2aae8..70fa653f7 100644 --- a/app/render/backend/opengl/opengltexture.h +++ b/app/render/backend/opengl/opengltexture.h @@ -44,6 +44,7 @@ public: void Create(QOpenGLContext* ctx, int width, int height, const PixelFormat::Format &format, const void *data, int linesize); void Create(QOpenGLContext* ctx, int width, int height, const PixelFormat::Format &format); void Create(QOpenGLContext* ctx, FramePtr frame); + void Create(QOpenGLContext* ctx, Frame* frame); bool IsCreated() const; @@ -59,6 +60,8 @@ public: const GLuint& texture() const; + void Upload(FramePtr frame); + void Upload(Frame* frame); void Upload(const void *data, int linesize); public slots: diff --git a/app/render/backend/opengl/opengltexturecache.cpp b/app/render/backend/opengl/opengltexturecache.cpp index 95e0638ee..a54994467 100644 --- a/app/render/backend/opengl/opengltexturecache.cpp +++ b/app/render/backend/opengl/opengltexturecache.cpp @@ -29,6 +29,16 @@ OpenGLTextureCache::~OpenGLTextureCache() } } +OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, const VideoRenderingParams ¶ms, FramePtr frame) +{ + return Get(ctx, params, frame.get()); +} + +OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext *ctx, const VideoRenderingParams ¶ms, Frame *frame) +{ + return Get(ctx, params, frame->data(), frame->linesize_pixels()); +} + OpenGLTextureCache::ReferencePtr OpenGLTextureCache::Get(QOpenGLContext* ctx, const VideoRenderingParams ¶ms, const void *data, int linesize) { OpenGLTexturePtr texture = nullptr; diff --git a/app/render/backend/opengl/opengltexturecache.h b/app/render/backend/opengl/opengltexturecache.h index 7be07bfbb..2baa87a67 100644 --- a/app/render/backend/opengl/opengltexturecache.h +++ b/app/render/backend/opengl/opengltexturecache.h @@ -57,6 +57,8 @@ public: DISABLE_COPY_MOVE(OpenGLTextureCache) + ReferencePtr Get(QOpenGLContext *ctx, const VideoRenderingParams& params, FramePtr frame); + ReferencePtr Get(QOpenGLContext *ctx, const VideoRenderingParams& params, Frame* frame); ReferencePtr Get(QOpenGLContext *ctx, const VideoRenderingParams& params, const void *data, int linesize); ReferencePtr Get(QOpenGLContext *ctx, const VideoRenderingParams& params); diff --git a/app/widget/curvewidget/curvewidget.cpp b/app/widget/curvewidget/curvewidget.cpp index 71c742619..b31e31ea8 100644 --- a/app/widget/curvewidget/curvewidget.cpp +++ b/app/widget/curvewidget/curvewidget.cpp @@ -200,6 +200,8 @@ void CurveWidget::ScaleChangedEvent(const double &scale) void CurveWidget::TimeTargetChangedEvent(Node *target) { + ConnectViewerNode(nullptr); + key_control_->SetTimeTarget(target); view_->SetTimeTarget(target); @@ -207,6 +209,12 @@ void CurveWidget::TimeTargetChangedEvent(Node *target) if (bridge_) { bridge_->SetTimeTarget(target); } + + // FIXME: If a non-viewer node is ever set here, it will fail to update the length + ViewerOutput* viewer = dynamic_cast(target); + if (viewer) { + ConnectViewerNode(viewer); + } } void CurveWidget::UpdateInputLabel() diff --git a/app/widget/manageddisplay/manageddisplay.cpp b/app/widget/manageddisplay/manageddisplay.cpp index 63cb2dd69..8d3d720fe 100644 --- a/app/widget/manageddisplay/manageddisplay.cpp +++ b/app/widget/manageddisplay/manageddisplay.cpp @@ -142,9 +142,13 @@ void ManagedDisplayWidget::MenuLookSelect(QAction *action) void ManagedDisplayWidget::SetColorTransform(const ColorTransform &transform) { + makeCurrent(); + color_transform_ = transform; SetupColorProcessor(); ColorProcessorChangedEvent(); + + doneCurrent(); } void ManagedDisplayWidget::initializeGL() @@ -248,9 +252,7 @@ void ManagedDisplayWidget::SetupColorProcessor() color_manager_->GetReferenceColorSpace(), color_transform_); - makeCurrent(); color_service_->Enable(context(), true); - doneCurrent(); } catch (OCIO::Exception& e) { diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index b9d1e7366..8675794c1 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -156,7 +156,9 @@ void NodeParamView::SetNodes(QList nodes) items_.append(item); - QTimer::singleShot(1, item, &NodeParamViewItem::SignalAllKeyframes); + QMetaObject::invokeMethod(item, + "SignalAllKeyframes", + Qt::QueuedConnection); emit OpenedNode(node); } @@ -218,6 +220,11 @@ const QList &NodeParamView::nodes() return nodes_; } +Node *NodeParamView::GetTimeTarget() const +{ + return keyframe_view_->GetTimeTarget(); +} + void NodeParamView::UpdateItemTime(const int64_t ×tamp) { rational time = Timecode::timestamp_to_time(timestamp, keyframe_view_->timebase()); diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index 097fcd4ae..be5cb5835 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -40,6 +40,8 @@ public: void SetNodes(QList nodes); const QList& nodes(); + Node* GetTimeTarget() const; + signals: void InputDoubleClicked(NodeInput* input); diff --git a/app/widget/scope/histogram/histogram.cpp b/app/widget/scope/histogram/histogram.cpp index ab7cb66e1..b9028f85a 100644 --- a/app/widget/scope/histogram/histogram.cpp +++ b/app/widget/scope/histogram/histogram.cpp @@ -49,7 +49,9 @@ void HistogramScope::SetBuffer(Frame* frame) { buffer_ = frame; - StartUpdate(); + if (isVisible()) { + StartUpdate(); + } } void HistogramScope::FinishedProcessing(QVector red, QVector green, QVector blue) @@ -111,6 +113,13 @@ void HistogramScope::StartUpdate() } } +void HistogramScope::showEvent(QShowEvent* e) +{ + ManagedDisplayWidget::showEvent(e); + + StartUpdate(); +} + HistogramScopeWorker::HistogramScopeWorker() : cancelled_(false) { diff --git a/app/widget/scope/histogram/histogram.h b/app/widget/scope/histogram/histogram.h index ea5175726..3efad3919 100644 --- a/app/widget/scope/histogram/histogram.h +++ b/app/widget/scope/histogram/histogram.h @@ -78,6 +78,8 @@ protected: virtual void ColorProcessorChangedEvent() override; + virtual void showEvent(QShowEvent* e) override; + private: void StartUpdate(); diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index 8a30dac66..0ce873bc5 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -28,16 +28,32 @@ OLIVE_NAMESPACE_ENTER WaveformScope::WaveformScope(QWidget* parent) : ManagedDisplayWidget(parent), - texture_(nullptr) + buffer_(nullptr) { EnableDefaultContextMenu(); } -void WaveformScope::SetTexture(OpenGLTexture *texture) +WaveformScope::~WaveformScope() { - texture_ = texture; + CleanUp(); - update(); + if (context()) { + disconnect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &WaveformScope::CleanUp); + } +} + +void WaveformScope::SetBuffer(Frame *frame) +{ + buffer_ = frame; + + UploadTextureFromBuffer(); +} + +void WaveformScope::showEvent(QShowEvent* e) +{ + ManagedDisplayWidget::showEvent(e); + + UploadTextureFromBuffer(); } void WaveformScope::initializeGL() @@ -49,37 +65,99 @@ void WaveformScope::initializeGL() pipeline_->addShaderFromSourceCode(QOpenGLShader::Vertex, OpenGLShader::CodeDefaultVertex()); pipeline_->addShaderFromSourceCode(QOpenGLShader::Fragment, Node::ReadFileAsString(":/shaders/rgbwaveform.frag")); pipeline_->link(); + + framebuffer_.Create(context()); + + connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &WaveformScope::CleanUp, Qt::DirectConnection); + + UploadTextureFromBuffer(); } void WaveformScope::paintGL() { - context()->functions()->glClearColor(0, 0, 0, 0); - context()->functions()->glClear(GL_COLOR_BUFFER_BIT); + QOpenGLFunctions* f = context()->functions(); - if (!pipeline_ || !texture_) { + f->glClearColor(0, 0, 0, 0); + f->glClear(GL_COLOR_BUFFER_BIT); + + if (!pipeline_ || !texture_.IsCreated()) { return; } - pipeline_->bind(); - pipeline_->setUniformValue("ove_resolution", texture_->width(), texture_->height()); - pipeline_->setUniformValue("ove_viewport", width(), height()); + { + // Convert reference frame to display space + framebuffer_.Attach(&managed_tex_); + framebuffer_.Bind(); - // The general size of a pixel - pipeline_->setUniformValue("threshold", 2.0f / static_cast(height())); + texture_.Bind(); - pipeline_->release(); + f->glViewport(0, 0, texture_.width(), texture_.height()); - texture_->Bind(); + color_service()->ProcessOpenGL(); - OpenGLRenderFunctions::Blit(pipeline_); + texture_.Release(); - texture_->Release(); + framebuffer_.Release(); + framebuffer_.Detach(); + } + + { + // Draw waveform through shader + pipeline_->bind(); + pipeline_->setUniformValue("ove_resolution", texture_.width(), texture_.height()); + pipeline_->setUniformValue("ove_viewport", width(), height()); + + // The general size of a pixel + pipeline_->setUniformValue("threshold", 2.0f / static_cast(height())); + + pipeline_->release(); + + f->glViewport(0, 0, width(), height()); + + managed_tex_.Bind(); + + OpenGLRenderFunctions::Blit(pipeline_); + + managed_tex_.Release(); + } +} + +void WaveformScope::UploadTextureFromBuffer() +{ + if (!buffer_ || !isVisible()) { + return; + } + + makeCurrent(); + + if (!texture_.IsCreated() + || texture_.width() != buffer_->width() + || texture_.height() != buffer_->height() + || texture_.format() != buffer_->format()) { + texture_.Destroy(); + managed_tex_.Destroy(); + + texture_.Create(context(), buffer_); + managed_tex_.Create(context(), buffer_->width(), buffer_->height(), buffer_->format()); + } else { + texture_.Upload(buffer_); + } + + doneCurrent(); + + update(); } void WaveformScope::CleanUp() { + makeCurrent(); + pipeline_ = nullptr; - texture_ = nullptr; + texture_.Destroy(); + managed_tex_.Destroy(); + framebuffer_.Destroy(); + + doneCurrent(); } OLIVE_NAMESPACE_EXIT diff --git a/app/widget/scope/waveform/waveform.h b/app/widget/scope/waveform/waveform.h index f9f930c5c..4243a9d3a 100644 --- a/app/widget/scope/waveform/waveform.h +++ b/app/widget/scope/waveform/waveform.h @@ -23,6 +23,7 @@ #include "codec/frame.h" #include "render/backend/opengl/openglcolorprocessor.h" +#include "render/backend/opengl/openglframebuffer.h" #include "render/backend/opengl/openglshader.h" #include "render/backend/opengl/opengltexture.h" #include "widget/manageddisplay/manageddisplay.h" @@ -35,18 +36,30 @@ class WaveformScope : public ManagedDisplayWidget public: WaveformScope(QWidget* parent = nullptr); + virtual ~WaveformScope() override; + public slots: - void SetTexture(OpenGLTexture* texture); + void SetBuffer(Frame* frame); protected: virtual void initializeGL() override; virtual void paintGL() override; + virtual void showEvent(QShowEvent* e) override; + private: + void UploadTextureFromBuffer(); + OpenGLShaderPtr pipeline_; - OpenGLTexture* texture_; + OpenGLTexture texture_; + + OpenGLTexture managed_tex_; + + OpenGLFramebuffer framebuffer_; + + Frame* buffer_; private slots: void CleanUp(); diff --git a/app/widget/viewer/manageddisplayobject.cpp b/app/widget/viewer/manageddisplayobject.cpp deleted file mode 100644 index f7541ca3f..000000000 --- a/app/widget/viewer/manageddisplayobject.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "manageddisplayobject.h" - -ManagedDisplayObject::ManagedDisplayObject() -{ - -} diff --git a/app/widget/viewer/manageddisplayobject.h b/app/widget/viewer/manageddisplayobject.h deleted file mode 100644 index 11de19c12..000000000 --- a/app/widget/viewer/manageddisplayobject.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef MANAGEDDISPLAYOBJECT_H -#define MANAGEDDISPLAYOBJECT_H - - -class ManagedDisplayObject -{ -public: - ManagedDisplayObject(); -}; - -#endif // MANAGEDDISPLAYOBJECT_H diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 4107ceab1..d4ebb84f0 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -66,8 +66,6 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(main_widget, &ViewerDisplayWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); connect(main_widget, &ViewerDisplayWidget::CursorColor, this, &ViewerWidget::CursorColor); connect(main_widget, &ViewerDisplayWidget::LoadedBuffer, this, &ViewerWidget::LoadedBuffer); - connect(main_widget, &ViewerDisplayWidget::LoadedTexture, this, &ViewerWidget::LoadedTexture); - connect(main_widget, &ViewerDisplayWidget::DrewManagedTexture, this, &ViewerWidget::DrewManagedTexture); connect(main_widget, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged); connect(main_widget, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged); connect(sizer_, &ViewerSizer::RequestMatrix, main_widget, &ViewerDisplayWidget::SetMatrix); @@ -745,11 +743,6 @@ void ViewerWidget::SetSignalCursorColorEnabled(bool e) } } -void ViewerWidget::SetEmitDrewManagedTextureEnabled(bool e) -{ - main_gl_widget()->SetEmitDrewManagedTextureEnabled(e); -} - void ViewerWidget::TimebaseChangedEvent(const rational &timebase) { TimeBasedWidget::TimebaseChangedEvent(timebase); diff --git a/app/widget/viewer/viewer.h b/app/widget/viewer/viewer.h index 8cf6bb24c..57b6e2970 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -107,11 +107,6 @@ public slots: */ void SetSignalCursorColorEnabled(bool e); - /** - * @brief Wrapper for ViewerGLWidget::SetEmitDrewManagedTextureEnabled() - */ - void SetEmitDrewManagedTextureEnabled(bool e); - signals: /** * @brief Wrapper for ViewerGLWidget::CursorColor() @@ -123,16 +118,6 @@ signals: */ void LoadedBuffer(Frame* load_buffer); - /** - * @brief Wrapper for ViewerGLWidget::LoadedTexture() - */ - void LoadedTexture(OpenGLTexture* texture); - - /** - * @brief Wrapper for ViewerGLWidget::DrewManagedTexture() - */ - void DrewManagedTexture(OpenGLTexture* texture); - /** * @brief Request a scope panel * diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 640539a61..779f65237 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -42,10 +42,8 @@ bool ViewerDisplayWidget::nouveau_check_done_ = false; ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : ManagedDisplayWidget(parent), - managed_copy_pipeline_(nullptr), has_image_(false), - signal_cursor_color_(false), - enable_display_referred_signal_(false) + signal_cursor_color_(false) { } @@ -91,14 +89,12 @@ void ViewerDisplayWidget::SetImage(const QString &fn) input->read_image(input->spec().format, load_buffer_.data(), OIIO::AutoStride, load_buffer_.linesize_bytes()); input->close(); - emit LoadedBuffer(&load_buffer_); - - texture_.Upload(load_buffer_.data(), load_buffer_.linesize_pixels()); - - emit LoadedTexture(&texture_); + texture_.Upload(&load_buffer_); doneCurrent(); + emit LoadedBuffer(&load_buffer_); + has_image_ = true; #if OIIO_VERSION < 10903 @@ -138,7 +134,7 @@ void ViewerDisplayWidget::SetImageFromLoadBuffer(Frame *in_buffer) || texture_.format() != in_buffer->format()) { texture_.Create(context(), in_buffer->width(), in_buffer->height(), in_buffer->format(), in_buffer->data(), load_buffer_.linesize_pixels()); } else { - texture_.Upload(in_buffer->data(), load_buffer_.linesize_pixels()); + texture_.Upload(in_buffer); } doneCurrent(); @@ -147,18 +143,6 @@ void ViewerDisplayWidget::SetImageFromLoadBuffer(Frame *in_buffer) update(); } -void ViewerDisplayWidget::SetEmitDrewManagedTextureEnabled(bool e) -{ - enable_display_referred_signal_ = e; - - if (!enable_display_referred_signal_) { - // Destroy the texture now - managed_texture_.Destroy(); - managed_copy_pipeline_ = nullptr; - framebuffer_.Destroy(); - } -} - void ViewerDisplayWidget::ConnectSibling(ViewerDisplayWidget *sibling) { connect(this, &ViewerDisplayWidget::LoadedBuffer, sibling, &ViewerDisplayWidget::SetImageFromLoadBuffer, Qt::QueuedConnection); @@ -243,33 +227,6 @@ void ViewerDisplayWidget::paintGL() // We only draw if we have a pipeline if (has_image_ && color_service() && texture_.IsCreated()) { - // If we're distributing our display-referred final buffer, we'll have to make a copy of it - if (enable_display_referred_signal_) { - - if (!managed_texture_.IsCreated() - || managed_texture_.width() != texture_.width() - || managed_texture_.height() != texture_.height() - || managed_texture_.format() != texture_.format()) { - managed_texture_.Destroy(); - - managed_texture_.Create(context(), texture_.width(), texture_.height(), texture_.format()); - } - - if (!managed_copy_pipeline_) { - managed_copy_pipeline_ = OpenGLShader::CreateDefault(); - } - - if (!framebuffer_.IsCreated()) { - framebuffer_.Create(context()); - } - - framebuffer_.Attach(&managed_texture_); - framebuffer_.Bind(); - - f->glViewport(0, 0, managed_texture_.width(), managed_texture_.height()); - - } - // Bind retrieved texture f->glBindTexture(GL_TEXTURE_2D, texture_.texture()); @@ -279,24 +236,6 @@ void ViewerDisplayWidget::paintGL() // Release retrieved texture f->glBindTexture(GL_TEXTURE_2D, 0); - if (enable_display_referred_signal_) { - - framebuffer_.Release(); - framebuffer_.Detach(); - - emit DrewManagedTexture(&managed_texture_); - - // Bind retrieved texture - managed_texture_.Bind(); - - f->glViewport(0, 0, width(), height()); - - OpenGLRenderFunctions::Blit(managed_copy_pipeline_); - - // Bind retrieved texture - managed_texture_.Release(); - - } } // Draw action/title safe areas @@ -348,10 +287,7 @@ void ViewerDisplayWidget::ContextCleanup() { makeCurrent(); - managed_copy_pipeline_ = nullptr; texture_.Destroy(); - managed_texture_.Destroy(); - framebuffer_.Destroy(); doneCurrent(); } diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 6289433a4..43e42eed2 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -101,15 +101,6 @@ public slots: */ void SetImageFromLoadBuffer(Frame* in_buffer); - /** - * @brief Enables or disables DrewManagedTexture() - * - * To emit a display referred texture, it needs to be copied after the color transform is complete. This naturally - * adds extra GPU cycles that are wasted if there's nothing receiving the signal. Therefore, the signal is disabled - * by default. - */ - void SetEmitDrewManagedTextureEnabled(bool e); - signals: /** * @brief Signal emitted when the user starts dragging from the viewer @@ -130,18 +121,6 @@ signals: */ void LoadedBuffer(Frame* load_buffer); - /** - * @brief Signal emitted when a buffer is loaded into a texture - * - * This texture will be the direct output of the renderer in reference space in GPU VRAM. - */ - void LoadedTexture(OpenGLTexture* texture); - - /** - * @brief Emitted when the a texture has been transformed to display - */ - void DrewManagedTexture(OpenGLTexture* texture); - protected: /** * @brief Override the mouse press event simply to emit the DragStarted() signal @@ -173,23 +152,6 @@ private: */ OpenGLTexture texture_; - /** - * @brief Internal framebuffer used to draw to managed_texture_ - */ - OpenGLFramebuffer framebuffer_; - - /** - * @brief Internal referenceto the OpenGL texture that's been managed - * - * Kept so that scopes can use the display-referred buffer without having to transform again. - */ - OpenGLTexture managed_texture_; - - /** - * @brief Pipeline used to draw to managed_texture_ - */ - OpenGLShaderPtr managed_copy_pipeline_; - /** * @brief Drawing matrix (defaults to identity) */ @@ -210,8 +172,6 @@ private: ViewerSafeMarginInfo safe_margin_; - bool enable_display_referred_signal_; - private slots: /** * @brief Slot to connect just before the OpenGL context is destroyed to clean up resources diff --git a/app/window/mainwindow/mainstatusbar.cpp b/app/window/mainwindow/mainstatusbar.cpp index 36a96d47b..568718e44 100644 --- a/app/window/mainwindow/mainstatusbar.cpp +++ b/app/window/mainwindow/mainstatusbar.cpp @@ -76,4 +76,11 @@ void MainStatusBar::UpdateStatus() } } +void MainStatusBar::mouseDoubleClickEvent(QMouseEvent* e) +{ + QStatusBar::mouseDoubleClickEvent(e); + + emit DoubleClicked(); +} + OLIVE_NAMESPACE_EXIT diff --git a/app/window/mainwindow/mainstatusbar.h b/app/window/mainwindow/mainstatusbar.h index 1a704860e..96e8dee5e 100644 --- a/app/window/mainwindow/mainstatusbar.h +++ b/app/window/mainwindow/mainstatusbar.h @@ -33,11 +33,18 @@ OLIVE_NAMESPACE_ENTER */ class MainStatusBar : public QStatusBar { + Q_OBJECT public: MainStatusBar(QWidget* parent = nullptr); void ConnectTaskManager(TaskManager* manager); +signals: + void DoubleClicked(); + +protected: + virtual void mouseDoubleClickEvent(QMouseEvent* e) override; + private slots: void UpdateStatus(); diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 4c192af99..bd375f994 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -33,18 +33,21 @@ OLIVE_NAMESPACE_ENTER MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { -#ifdef Q_OS_WINDOWS - // Qt on Windows has a bug that "de-maximizes" the window when widgets are added, resizing the window beforehand - // works around that issue and we just set it to whatever size is available + // Resizes main window to desktop geometry on startup. Fixes the following issues: + // * Qt on Windows has a bug that "de-maximizes" the window when widgets are added, resizing the + // window beforehand works around that issue and we just set it to whatever size is available. + // * On Linux, it seems the window starts off at a vastly different size and then maximizes + // which throws off the proportions and makes the resulting layout wonky. resize(qApp->desktop()->availableGeometry(this).size()); +#ifdef Q_OS_WINDOWS // Set up taskbar button progress bar (used for some modal tasks like exporting) taskbar_btn_id_ = RegisterWindowMessage("TaskbarButtonCreated"); taskbar_interface_ = nullptr; #endif - // Create empty central widget - we don't actually want a central widget but some of Qt's docking/undocking fails - // without it + // Create empty central widget - we don't actually want a central widget (so we set its maximum + // size to 0,0) but some of Qt's docking/undocking fails without it QWidget* centralWidget = new QWidget(this); centralWidget->setMaximumSize(QSize(0, 0)); setCentralWidget(centralWidget); @@ -62,6 +65,7 @@ MainWindow::MainWindow(QWidget *parent) : // Create and set status bar MainStatusBar* status_bar = new MainStatusBar(this); status_bar->ConnectTaskManager(TaskManager::instance()); + connect(status_bar, &MainStatusBar::DoubleClicked, this, &MainWindow::StatusBarDoubleClicked); setStatusBar(status_bar); // Create standard panels @@ -389,6 +393,12 @@ bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *r } #endif +void MainWindow::StatusBarDoubleClicked() +{ + task_man_panel_->show(); + task_man_panel_->raise(); +} + void MainWindow::UpdateTitle() { if (Core::instance()->GetActiveProject()) { diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index cbf2ccc26..362b88ca4 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -150,6 +150,8 @@ private slots: void LoadLayoutInternal(QXmlStreamReader* reader, XMLNodeData *xml_data); + void StatusBarDoubleClicked(); + }; OLIVE_NAMESPACE_EXIT diff --git a/cmake/MacOSXBundleInfo.plist.in b/cmake/MacOSXBundleInfo.plist.in new file mode 100644 index 000000000..ae08eb0d9 --- /dev/null +++ b/cmake/MacOSXBundleInfo.plist.in @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + CSResourcesFileMapped + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + NSPrincipalClass + NSApplication + +