scope: implemented waveform scope

This commit is contained in:
itsmattkc
2020-04-20 22:58:29 +10:00
parent 9db82ddc2e
commit 6f4bf70d3e
30 changed files with 800 additions and 18 deletions
+3
View File
@@ -50,6 +50,9 @@ int main(int argc, char *argv[]) {
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);
// Try to share OpenGL contexts
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
// Create application instance
QApplication a(argc, argv);
+1
View File
@@ -21,6 +21,7 @@ add_subdirectory(node)
add_subdirectory(param)
add_subdirectory(pixelsampler)
add_subdirectory(project)
add_subdirectory(scope)
add_subdirectory(sequenceviewer)
add_subdirectory(taskmanager)
add_subdirectory(timebased)
+3 -1
View File
@@ -28,7 +28,9 @@ FootageViewerPanel::FootageViewerPanel(QWidget *parent) :
ViewerPanelBase(QStringLiteral("FootageViewerPanel"), parent)
{
// Set ViewerWidget as the central widget
SetTimeBasedWidget(new FootageViewerWidget());
FootageViewerWidget* fvw = new FootageViewerWidget();
connect(fvw, &FootageViewerWidget::RequestScopePanel, this, &FootageViewerPanel::CreateScopePanel);
SetTimeBasedWidget(fvw);
// Set strings
Retranslate();
+3 -1
View File
@@ -40,7 +40,9 @@ ProjectPanel::ProjectPanel(QWidget *parent) :
// Create main widget and its layout
QWidget* central_widget = new QWidget(this);
QVBoxLayout* layout = new QVBoxLayout(central_widget);
setWidget(central_widget);
layout->setMargin(0);
SetWidgetWithPadding(central_widget);
// Set up project toolbar
ProjectToolbar* toolbar = new ProjectToolbar(this);
+22
View File
@@ -0,0 +1,22 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2019 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
panel/scope/scope.h
panel/scope/scope.cpp
PARENT_SCOPE
)
+100
View File
@@ -0,0 +1,100 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "scope.h"
#include <QVBoxLayout>
#include "panel/viewer/viewer.h"
OLIVE_NAMESPACE_ENTER
ScopePanel::ScopePanel(QWidget* parent) :
PanelWidget(QStringLiteral("ScopePanel"), parent)
{
QWidget* central = new QWidget();
setWidget(central);
QVBoxLayout* layout = new QVBoxLayout(central);
QHBoxLayout* toolbar_layout = new QHBoxLayout();
toolbar_layout->setMargin(0);
scope_type_combobox_ = new QComboBox();
for (int i=0;i<ScopePanel::kTypeCount;i++) {
// These strings get filled in later in Retranslate()
scope_type_combobox_->addItem(QString());
}
toolbar_layout->addWidget(scope_type_combobox_);
toolbar_layout->addStretch();
layout->addLayout(toolbar_layout);
stack_ = new QStackedWidget();
layout->addWidget(stack_);
// Create waveform view
waveform_view_ = new WaveformScope();
stack_->addWidget(waveform_view_);
// Create histogram
stack_->addWidget(new QWidget());
connect(scope_type_combobox_, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), stack_, &QStackedWidget::setCurrentIndex);
Retranslate();
}
void ScopePanel::SetType(ScopePanel::Type t)
{
scope_type_combobox_->setCurrentIndex(t);
}
QString ScopePanel::TypeToName(ScopePanel::Type t)
{
switch (t) {
case kTypeWaveform:
return tr("Waveform");
case kTypeHistogram:
return tr("Histogram");
case kTypeCount:
break;
}
return QString();
}
void ScopePanel::DrewManagedTexture(OpenGLTexture *texture)
{
waveform_view_->SetTexture(texture);
}
void ScopePanel::Retranslate()
{
SetTitle(tr("Scope"));
for (int i=0;i<ScopePanel::kTypeCount;i++) {
scope_type_combobox_->setItemText(i, TypeToName(static_cast<Type>(i)));
}
}
OLIVE_NAMESPACE_EXIT
+70
View File
@@ -0,0 +1,70 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef SCOPE_PANEL_H
#define SCOPE_PANEL_H
#include <QComboBox>
#include <QStackedWidget>
#include "widget/panel/panel.h"
#include "widget/scope/waveform/waveform.h"
OLIVE_NAMESPACE_ENTER
class ViewerPanel;
class ScopePanel : public PanelWidget
{
Q_OBJECT
public:
enum Type {
kTypeWaveform,
kTypeHistogram,
kTypeCount
};
ScopePanel(QWidget* parent = nullptr);
void SetType(Type t);
static QString TypeToName(Type t);
public slots:
void DrewManagedTexture(OpenGLTexture* texture);
protected:
virtual void Retranslate() override;
private:
Type type_;
QStackedWidget* stack_;
QComboBox* scope_type_combobox_;
WaveformScope* waveform_view_;
};
OLIVE_NAMESPACE_EXIT
#endif // SCOPE_PANEL_H
+1 -1
View File
@@ -70,7 +70,7 @@ void TimeBasedPanel::SetTimebase(const rational &timebase)
void TimeBasedPanel::SetTime(const int64_t &timestamp)
{
widget_->SetTime(timestamp);
widget_->SetTimestamp(timestamp);
}
void TimeBasedPanel::GoToPrevCut()
+3 -1
View File
@@ -26,7 +26,9 @@ ViewerPanel::ViewerPanel(const QString &object_name, QWidget *parent) :
ViewerPanelBase(object_name, parent)
{
// Set ViewerWidget as the central widget
SetTimeBasedWidget(new ViewerWidget());
ViewerWidget* vw = new ViewerWidget();
connect(vw, &ViewerWidget::RequestScopePanel, this, &ViewerPanel::CreateScopePanel);
SetTimeBasedWidget(vw);
// Set strings
Retranslate();
+38 -1
View File
@@ -20,10 +20,13 @@
#include "viewerbase.h"
#include "window/mainwindow/mainwindow.h"
OLIVE_NAMESPACE_ENTER
ViewerPanelBase::ViewerPanelBase(const QString& object_name, QWidget *parent) :
TimeBasedPanel(object_name, parent)
TimeBasedPanel(object_name, parent),
scope_panel_count_(0)
{
}
@@ -88,4 +91,38 @@ void ViewerPanelBase::SetFullScreen(QScreen *screen)
static_cast<ViewerWidget*>(GetTimeBasedWidget())->SetFullScreen(screen);
}
void ViewerPanelBase::CreateScopePanel(ScopePanel::Type type)
{
ViewerWidget* vw = static_cast<ViewerWidget*>(GetTimeBasedWidget());
ScopePanel* p = Core::instance()->main_window()->AppendScopePanel();
p->SetType(type);
// We treat our scope panels as kind of children, and destroy them if we're ever destroyed
connect(this, &ViewerPanelBase::destroyed, p, &ScopePanel::deleteLater);
// 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::DrewManagedTexture);
if (!scope_panel_count_) {
vw->SetEmitDrewManagedTextureEnabled(true);
}
scope_panel_count_++;
vw->ForceUpdate();
}
void ViewerPanelBase::ScopePanelClosed()
{
scope_panel_count_--;
if (!scope_panel_count_) {
static_cast<ViewerWidget*>(GetTimeBasedWidget())->SetEmitDrewManagedTextureEnabled(false);
}
}
OLIVE_NAMESPACE_EXIT
+9
View File
@@ -56,6 +56,15 @@ public:
*/
void SetFullScreen(QScreen* screen = nullptr);
protected:
void CreateScopePanel(ScopePanel::Type type);
private:
int scope_panel_count_;
private slots:
void ScopePanelClosed();
};
OLIVE_NAMESPACE_EXIT
+29
View File
@@ -0,0 +1,29 @@
// Adapted from "RGB Waveform" by lebek
// https://www.shadertoy.com/view/4dK3Wc
#version 110
uniform sampler2D ove_maintex;
uniform vec2 ove_resolution;
varying vec2 ove_texcoord;
uniform float threshold;
void main(void) {
vec3 col = vec3(0.0);
float s = ove_texcoord.y*1.8 - 0.15;
float maxb = s+threshold;
float minb = s-threshold;
int y_lim = int(ove_resolution.y);
for (int i = 0; i < y_lim; i++) {
vec3 x = texture2D(ove_maintex, vec2(ove_texcoord.x, float(i)/float(ove_resolution.y))).rgb;
col += step(x, vec3(maxb))*step(vec3(minb), x) / (ove_resolution.y * 0.125);
float l = dot(x, x);
col += step(l, maxb*maxb)*step(minb*minb, l) / (ove_resolution.y * 0.125);
}
gl_FragColor = vec4(col, 1.0);
}
+1
View File
@@ -12,6 +12,7 @@
<file>dropshadow.xml</file>
<file>diptoblack.frag</file>
<file>diptoblack.xml</file>
<file>rgbwaveform.frag</file>
<file>solid.frag</file>
<file>solid.xml</file>
<file>stroke.frag</file>
+1
View File
@@ -34,6 +34,7 @@ add_subdirectory(playbackcontrols)
add_subdirectory(projectexplorer)
add_subdirectory(projecttoolbar)
add_subdirectory(resizablescrollbar)
add_subdirectory(scope)
add_subdirectory(slider)
add_subdirectory(taskview)
add_subdirectory(timebased)
+1 -1
View File
@@ -79,7 +79,7 @@ NodeParamView::NodeParamView(QWidget *parent) :
// Connect ruler and keyframe view together
connect(ruler(), &TimeRuler::TimeChanged, keyframe_view_, &KeyframeView::SetTime);
connect(keyframe_view_, &KeyframeView::TimeChanged, ruler(), &TimeRuler::SetTime);
connect(keyframe_view_, &KeyframeView::TimeChanged, this, &NodeParamView::SetTime);
connect(keyframe_view_, &KeyframeView::TimeChanged, this, &NodeParamView::SetTimestamp);
// Connect keyframe view scaling to this
connect(keyframe_view_, &KeyframeView::ScaleChanged, this, &NodeParamView::SetScale);
+23
View File
@@ -0,0 +1,23 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2019 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(histogram)
add_subdirectory(waveform)
set(OLIVE_SOURCES
${OLIVE_SOURCES}
PARENT_SCOPE
)
+22
View File
@@ -0,0 +1,22 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2019 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/scope/histogram/histogram.h
widget/scope/histogram/histogram.cpp
PARENT_SCOPE
)
+42
View File
@@ -0,0 +1,42 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "histogram.h"
OLIVE_NAMESPACE_ENTER
HistogramScope::HistogramScope(QWidget* parent) :
QOpenGLWidget(parent)
{
}
void HistogramScope::SetBuffer(Frame* frame)
{
buffer_ = frame;
update();
}
void HistogramScope::paintGL()
{
//QPainter p(this);
}
OLIVE_NAMESPACE_EXIT
+49
View File
@@ -0,0 +1,49 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef HISTOGRAMSCOPE_H
#define HISTOGRAMSCOPE_H
#include <QOpenGLWidget>
#include "codec/frame.h"
OLIVE_NAMESPACE_ENTER
class HistogramScope : public QOpenGLWidget
{
Q_OBJECT
public:
HistogramScope(QWidget* parent = nullptr);
public slots:
void SetBuffer(Frame* frame);
protected:
virtual void paintGL() override;
private:
Frame* buffer_;
};
OLIVE_NAMESPACE_EXIT
#endif // HISTOGRAMSCOPE_H
+22
View File
@@ -0,0 +1,22 @@
# Olive - Non-Linear Video Editor
# Copyright (C) 2019 Olive Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/scope/waveform/waveform.h
widget/scope/waveform/waveform.cpp
PARENT_SCOPE
)
+82
View File
@@ -0,0 +1,82 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "waveform.h"
#include "node/node.h"
#include "render/backend/opengl/openglrenderfunctions.h"
OLIVE_NAMESPACE_ENTER
WaveformScope::WaveformScope(QWidget* parent) :
QOpenGLWidget(parent),
texture_(nullptr)
{
}
void WaveformScope::SetTexture(OpenGLTexture *texture)
{
texture_ = texture;
update();
}
void WaveformScope::initializeGL()
{
pipeline_ = OpenGLShader::Create();
pipeline_->create();
pipeline_->addShaderFromSourceCode(QOpenGLShader::Vertex, OpenGLShader::CodeDefaultVertex());
pipeline_->addShaderFromSourceCode(QOpenGLShader::Fragment, Node::ReadFileAsString(":/shaders/rgbwaveform.frag"));
pipeline_->link();
}
void WaveformScope::paintGL()
{
context()->functions()->glClearColor(0, 0, 0, 0);
context()->functions()->glClear(GL_COLOR_BUFFER_BIT);
if (!pipeline_ || !texture_) {
return;
}
pipeline_->bind();
pipeline_->setUniformValue("ove_resolution", texture_->width(), texture_->height());
// The general size of a pixel
pipeline_->setUniformValue("threshold", 2.0f / static_cast<float>(height()));
pipeline_->release();
texture_->Bind();
OpenGLRenderFunctions::Blit(pipeline_);
texture_->Release();
}
void WaveformScope::CleanUp()
{
pipeline_ = nullptr;
texture_ = nullptr;
}
OLIVE_NAMESPACE_EXIT
+59
View File
@@ -0,0 +1,59 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2019 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef WAVEFORMSCOPE_H
#define WAVEFORMSCOPE_H
#include <QOpenGLWidget>
#include "codec/frame.h"
#include "render/backend/opengl/openglcolorprocessor.h"
#include "render/backend/opengl/openglshader.h"
#include "render/backend/opengl/opengltexture.h"
OLIVE_NAMESPACE_ENTER
class WaveformScope : public QOpenGLWidget
{
Q_OBJECT
public:
WaveformScope(QWidget* parent = nullptr);
public slots:
void SetTexture(OpenGLTexture* texture);
protected:
virtual void initializeGL() override;
virtual void paintGL() override;
private:
OpenGLShaderPtr pipeline_;
OpenGLTexture* texture_;
private slots:
void CleanUp();
};
OLIVE_NAMESPACE_EXIT
#endif // WAVEFORMSCOPE_H
+2 -2
View File
@@ -204,7 +204,7 @@ void TimeBasedWidget::ConnectTimelineView(TimelineViewBase *base)
timeline_views_.append(base);
}
void TimeBasedWidget::SetTime(int64_t timestamp)
void TimeBasedWidget::SetTimestamp(int64_t timestamp)
{
ruler_->SetTime(timestamp);
@@ -325,7 +325,7 @@ void TimeBasedWidget::GoToEnd()
void TimeBasedWidget::SetTimeAndSignal(const int64_t &t)
{
SetTime(t);
SetTimestamp(t);
emit TimeChanged(t);
}
+1 -2
View File
@@ -53,8 +53,7 @@ public:
void SetScaleAndCenterOnPlayhead(const double& scale);
public slots:
// FIXME: Rename this to SetTimestamp to reduce confusion
void SetTime(int64_t timestamp);
void SetTimestamp(int64_t timestamp);
void SetTimebase(const rational& timebase);
+37 -3
View File
@@ -37,6 +37,7 @@
#include "project/project.h"
#include "render/pixelformat.h"
#include "widget/menu/menu.h"
#include "window/mainwindow/mainwindow.h"
OLIVE_NAMESPACE_ENTER
@@ -64,6 +65,9 @@ ViewerWidget::ViewerWidget(QWidget *parent) :
ViewerGLWidget* main_widget = new ViewerGLWidget();
connect(main_widget, &ViewerGLWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu);
connect(main_widget, &ViewerGLWidget::CursorColor, this, &ViewerWidget::CursorColor);
connect(main_widget, &ViewerGLWidget::LoadedBuffer, this, &ViewerWidget::LoadedBuffer);
connect(main_widget, &ViewerGLWidget::LoadedTexture, this, &ViewerWidget::LoadedTexture);
connect(main_widget, &ViewerGLWidget::DrewManagedTexture, this, &ViewerWidget::DrewManagedTexture);
connect(sizer_, &ViewerSizer::RequestMatrix, main_widget, &ViewerGLWidget::SetMatrix);
sizer_->SetWidget(main_widget);
gl_widgets_.append(main_widget);
@@ -259,7 +263,7 @@ void ViewerWidget::ConnectViewerNode(ViewerOutput *node, ColorManager* color_man
TimeBasedWidget::ConnectViewerNode(node);
// Set texture to new texture (or null if no viewer node is available)
UpdateTextureFromNode(GetTime());
ForceUpdate();
}
void ViewerWidget::SetColorMenuEnabled(bool enabled)
@@ -313,6 +317,12 @@ void ViewerWidget::SetFullScreen(QScreen *screen)
gl_widgets_.append(vw->gl_widget());
}
void ViewerWidget::ForceUpdate()
{
// Hack that forces the viewer to update
UpdateTextureFromNode(GetTime());
}
VideoRenderBackend *ViewerWidget::video_renderer() const
{
return video_renderer_;
@@ -458,7 +468,6 @@ void ViewerWidget::ContextMenuSetCustomSafeMargins()
if (ratio_components.size() == 2) {
bool numer_ok, denom_ok;
// FIXME: Won't accept decimals like 2.39:1
double num = ratio_components.at(0).toDouble(&numer_ok);
double den = ratio_components.at(1).toDouble(&denom_ok);
@@ -486,6 +495,11 @@ void ViewerWidget::WindowAboutToClose()
gl_widgets_.removeAll(vw->gl_widget());
}
void ViewerWidget::ContextMenuScopeTriggered(QAction *action)
{
emit RequestScopePanel(static_cast<ScopePanel::Type>(action->data().toInt()));
}
void ViewerWidget::UpdateRendererParameters()
{
if (!GetConnectedNode()) {
@@ -626,6 +640,21 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos)
menu.addSeparator();
{
// Scopes
Menu* scopes_menu = new Menu(tr("Scopes"), &menu);
menu.addMenu(scopes_menu);
for (int i=0;i<ScopePanel::kTypeCount;i++) {
QAction* scope_action = scopes_menu->addAction(ScopePanel::TypeToName(static_cast<ScopePanel::Type>(i)));
scope_action->setData(i);
}
connect(scopes_menu, &Menu::triggered, this, &ViewerWidget::ContextMenuScopeTriggered);
}
menu.addSeparator();
{
// Safe Margins
Menu* safe_margin_menu = new Menu(tr("Safe Margins"), &menu);
@@ -768,6 +797,11 @@ void ViewerWidget::SetSignalCursorColorEnabled(bool e)
}
}
void ViewerWidget::SetEmitDrewManagedTextureEnabled(bool e)
{
main_gl_widget()->SetEmitDrewManagedTextureEnabled(e);
}
void ViewerWidget::TimebaseChangedEvent(const rational &timebase)
{
TimeBasedWidget::TimebaseChangedEvent(timebase);
@@ -852,7 +886,7 @@ void ViewerWidget::RendererCachedTime(const rational &time, qint64 job_time)
if (GetTime() == time && job_time > frame_cache_job_time_) {
frame_cache_job_time_ = job_time;
UpdateTextureFromNode(GetTime());
ForceUpdate();
}
}
+32
View File
@@ -31,6 +31,7 @@
#include "audiowaveformview.h"
#include "common/rational.h"
#include "node/output/viewer/viewer.h"
#include "panel/scope/scope.h"
#include "render/backend/opengl/openglbackend.h"
#include "render/backend/opengl/opengltexture.h"
#include "render/backend/audio/audiobackend.h"
@@ -80,6 +81,8 @@ public:
*/
void SetFullScreen(QScreen* screen = nullptr);
void ForceUpdate();
VideoRenderBackend* video_renderer() const;
public slots:
@@ -123,12 +126,39 @@ public slots:
*/
void SetSignalCursorColorEnabled(bool e);
/**
* @brief Wrapper for ViewerGLWidget::SetEmitDrewManagedTextureEnabled()
*/
void SetEmitDrewManagedTextureEnabled(bool e);
signals:
/**
* @brief Wrapper for ViewerGLWidget::CursorColor()
*/
void CursorColor(const Color& reference, const Color& display);
/**
* @brief Wrapper for ViewerGLWidget::LoadedBuffer()
*/
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
*
* As a widget, we don't handle panels, but a parent panel may pick this signal up.
*/
void RequestScopePanel(ScopePanel::Type type);
protected:
virtual void TimebaseChangedEvent(const rational &) override;
virtual void TimeChangedEvent(const int64_t &) override;
@@ -244,6 +274,8 @@ private slots:
void WindowAboutToClose();
void ContextMenuScopeTriggered(QAction* action);
};
OLIVE_NAMESPACE_EXIT
+68 -2
View File
@@ -42,9 +42,11 @@ bool ViewerGLWidget::nouveau_check_done_ = false;
ViewerGLWidget::ViewerGLWidget(QWidget *parent) :
QOpenGLWidget(parent),
managed_copy_pipeline_(nullptr),
color_manager_(nullptr),
has_image_(false),
signal_cursor_color_(false)
signal_cursor_color_(false),
enable_display_referred_signal_(false)
{
setContextMenuPolicy(Qt::CustomContextMenu);
}
@@ -115,9 +117,11 @@ void ViewerGLWidget::SetImage(const QString &fn)
input->read_image(input->spec().format, load_buffer_.data());
input->close();
emit LoadedBuffer(&load_buffer_);
texture_.Upload(load_buffer_.data());
emit LoadedBuffer(&load_buffer_);
emit LoadedTexture(&texture_);
doneCurrent();
@@ -169,6 +173,18 @@ void ViewerGLWidget::SetImageFromLoadBuffer(Frame *in_buffer)
update();
}
void ViewerGLWidget::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 ViewerGLWidget::SetOCIODisplay(const QString &display)
{
ocio_display_ = display;
@@ -310,6 +326,34 @@ void ViewerGLWidget::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();
context()->functions()->glViewport(0, 0, managed_texture_.width(), managed_texture_.height());
}
// Bind retrieved texture
f->glBindTexture(GL_TEXTURE_2D, texture_.texture());
@@ -318,6 +362,25 @@ void ViewerGLWidget::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();
context()->functions()->glViewport(0, 0, width(), height());
OpenGLRenderFunctions::Blit(managed_copy_pipeline_);
// Bind retrieved texture
managed_texture_.Release();
}
}
// Draw action/title safe areas
@@ -433,7 +496,10 @@ void ViewerGLWidget::ContextCleanup()
makeCurrent();
color_service_ = nullptr;
managed_copy_pipeline_ = nullptr;
texture_.Destroy();
managed_texture_.Destroy();
framebuffer_.Destroy();
doneCurrent();
}
+45 -1
View File
@@ -148,6 +148,15 @@ 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
@@ -160,10 +169,26 @@ signals:
void CursorColor(const Color& reference, const Color& display);
/**
* @brief Connect this to the SetImageFromLoadBuffer() slot of another ViewerGLWidget to show the same thing
* @brief Signal emitted when a buffer is loaded from file into memory
*
* This buffer will be the direct output of the renderer in reference space in CPU memory.
*
* Connect this to the SetImageFromLoadBuffer() slot of another ViewerGLWidget to show the same thing
*/
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
@@ -220,6 +245,23 @@ 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 Connected color manager
*/
@@ -250,6 +292,8 @@ 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
+23
View File
@@ -244,6 +244,21 @@ void MainWindow::FolderOpen(Project* p, Item *i, bool floating)
folder_panels_.append(panel);
}
ScopePanel *MainWindow::AppendScopePanel()
{
ScopePanel* panel = PanelManager::instance()->CreatePanel<ScopePanel>(this);
SetUniquePanelID(panel, scope_panels_);
panel->setFloating(true);
panel->show();
panel->SetSignalInsteadOfClose(true);
connect(panel, &ScopePanel::CloseRequested, this, &MainWindow::ScopeCloseRequested);
return panel;
}
void MainWindow::SetFullscreen(bool fullscreen)
{
if (fullscreen) {
@@ -408,6 +423,14 @@ void MainWindow::FolderCloseRequested()
panel->deleteLater();
}
void MainWindow::ScopeCloseRequested()
{
ScopePanel* panel = static_cast<ScopePanel*>(sender());
scope_panels_.removeOne(panel);
panel->deleteLater();
}
void MainWindow::LoadLayoutInternal(QXmlStreamReader *reader, XMLNodeData *xml_data)
{
while (XMLReadNextStartElement(reader)) {
+8 -2
View File
@@ -29,6 +29,7 @@
#include "panel/node/node.h"
#include "panel/param/param.h"
#include "panel/project/project.h"
#include "panel/scope/scope.h"
#include "panel/taskmanager/taskmanager.h"
#include "panel/timeline/timeline.h"
#include "panel/tool/tool.h"
@@ -63,14 +64,16 @@ public:
bool IsSequenceOpen(Sequence* sequence) const;
void FolderOpen(Project* p, Item* i, bool floating);
ScopePanel* AppendScopePanel();
#ifdef Q_OS_WINDOWS
void SetTaskbarButtonState(TBPFLAG flags);
void SetTaskbarButtonProgress(int value, int max);
#endif
void FolderOpen(Project* p, Item* i, bool floating);
public slots:
void ProjectOpen(Project *p);
@@ -121,6 +124,7 @@ private:
TaskManagerPanel* task_man_panel_;
CurvePanel* curve_panel_;
PixelSamplerPanel* pixel_sampler_panel_;
QList<ScopePanel*> scope_panels_;
#ifdef Q_OS_WINDOWS
unsigned int taskbar_btn_id_;
@@ -139,6 +143,8 @@ private slots:
void FolderCloseRequested();
void ScopeCloseRequested();
void LoadLayoutInternal(QXmlStreamReader* reader, XMLNodeData *xml_data);
};