From 6ea6dd810e07957fb73510d1cd83dec08c1cd23b Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 1 Apr 2020 16:57:10 +1100 Subject: [PATCH] pixelsampler: added pixel sampler panel When visible, this panel will show the current reference and display transformed color under the cursor of any viewer. --- app/codec/frame.cpp | 18 ++++++ app/codec/frame.h | 4 ++ app/panel/CMakeLists.txt | 1 + app/panel/pixelsampler/CMakeLists.txt | 22 ++++++++ app/panel/pixelsampler/pixelsamplerpanel.cpp | 23 ++++++++ app/panel/pixelsampler/pixelsamplerpanel.h | 23 ++++++++ app/panel/viewer/viewerbase.cpp | 8 +++ app/panel/viewer/viewerbase.h | 3 + app/render/CMakeLists.txt | 2 + .../backend/opengl/openglframebuffer.cpp | 7 ++- app/render/backend/opengl/openglframebuffer.h | 3 +- app/render/color.cpp | 14 +++++ app/render/color.h | 50 +++++++++++++++++ app/render/colorprocessor.cpp | 6 ++ app/render/colorprocessor.h | 4 +- app/render/pixelformat.cpp | 44 --------------- app/widget/viewer/CMakeLists.txt | 2 + app/widget/viewer/pixelsamplerwidget.cpp | 55 +++++++++++++++++++ app/widget/viewer/pixelsamplerwidget.h | 44 +++++++++++++++ app/widget/viewer/viewer.cpp | 6 ++ app/widget/viewer/viewer.h | 11 ++++ app/widget/viewer/viewerglwidget.cpp | 48 +++++++++++++++- app/widget/viewer/viewerglwidget.h | 31 +++++++++++ app/window/mainwindow/mainwindow.cpp | 7 +++ app/window/mainwindow/mainwindow.h | 2 + 25 files changed, 390 insertions(+), 48 deletions(-) create mode 100644 app/panel/pixelsampler/CMakeLists.txt create mode 100644 app/panel/pixelsampler/pixelsamplerpanel.cpp create mode 100644 app/panel/pixelsampler/pixelsamplerpanel.h create mode 100644 app/render/color.cpp create mode 100644 app/render/color.h create mode 100644 app/widget/viewer/pixelsamplerwidget.cpp create mode 100644 app/widget/viewer/pixelsamplerwidget.h diff --git a/app/codec/frame.cpp b/app/codec/frame.cpp index bc2ee45ab..b19ae2b04 100644 --- a/app/codec/frame.cpp +++ b/app/codec/frame.cpp @@ -59,6 +59,24 @@ const PixelFormat::Format &Frame::format() const return params_.format(); } +Color Frame::get_pixel(int x, int y) const +{ + if (!contains_pixel(x, y)) { + return Color(); + } + + int pixel_index = y * width() + x; + + int byte_offset = PixelFormat::GetBufferSize(video_params().format(), pixel_index, 1); + + return Color(data_.data() + byte_offset, video_params().format()); +} + +bool Frame::contains_pixel(int x, int y) const +{ + return (is_allocated() && x >= 0 && x < width() && y >= 0 && y < height()); +} + const rational &Frame::sample_aspect_ratio() const { return sample_aspect_ratio_; diff --git a/app/codec/frame.h b/app/codec/frame.h index fe95ab05f..adf1bab82 100644 --- a/app/codec/frame.h +++ b/app/codec/frame.h @@ -25,6 +25,7 @@ #include #include "common/rational.h" +#include "render/color.h" #include "render/pixelformat.h" #include "render/videoparams.h" @@ -48,6 +49,9 @@ public: const int& height() const; const PixelFormat::Format& format() const; + Color get_pixel(int x, int y) const; + bool contains_pixel(int x, int y) const; + const rational& sample_aspect_ratio() const; void set_sample_aspect_ratio(const rational& sample_aspect_ratio); diff --git a/app/panel/CMakeLists.txt b/app/panel/CMakeLists.txt index 5ffe1441d..5d90f94b5 100644 --- a/app/panel/CMakeLists.txt +++ b/app/panel/CMakeLists.txt @@ -19,6 +19,7 @@ add_subdirectory(curve) add_subdirectory(footageviewer) add_subdirectory(node) add_subdirectory(param) +add_subdirectory(pixelsampler) add_subdirectory(project) add_subdirectory(sequenceviewer) add_subdirectory(taskmanager) diff --git a/app/panel/pixelsampler/CMakeLists.txt b/app/panel/pixelsampler/CMakeLists.txt new file mode 100644 index 000000000..e10db4b54 --- /dev/null +++ b/app/panel/pixelsampler/CMakeLists.txt @@ -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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + panel/pixelsampler/pixelsamplerpanel.h + panel/pixelsampler/pixelsamplerpanel.cpp + PARENT_SCOPE +) diff --git a/app/panel/pixelsampler/pixelsamplerpanel.cpp b/app/panel/pixelsampler/pixelsamplerpanel.cpp new file mode 100644 index 000000000..5e9a00001 --- /dev/null +++ b/app/panel/pixelsampler/pixelsamplerpanel.cpp @@ -0,0 +1,23 @@ +#include "pixelsamplerpanel.h" + +PixelSamplerPanel::PixelSamplerPanel(QWidget *parent) : + PanelWidget(parent) +{ + // FIXME: This won't work if there's ever more than one of this panel + setObjectName("ProjectPanel"); + + sampler_widget_ = new ManagedPixelSamplerWidget(); + setWidget(sampler_widget_); + + Retranslate(); +} + +void PixelSamplerPanel::SetValues(const Color &reference, const Color &display) +{ + sampler_widget_->SetValues(reference, display); +} + +void PixelSamplerPanel::Retranslate() +{ + SetTitle(tr("Pixel Sampler")); +} diff --git a/app/panel/pixelsampler/pixelsamplerpanel.h b/app/panel/pixelsampler/pixelsamplerpanel.h new file mode 100644 index 000000000..d645ea834 --- /dev/null +++ b/app/panel/pixelsampler/pixelsamplerpanel.h @@ -0,0 +1,23 @@ +#ifndef PIXELSAMPLERPANEL_H +#define PIXELSAMPLERPANEL_H + +#include "widget/panel/panel.h" +#include "widget/viewer/pixelsamplerwidget.h" + +class PixelSamplerPanel : public PanelWidget +{ + Q_OBJECT +public: + PixelSamplerPanel(QWidget* parent = nullptr); + +public slots: + void SetValues(const Color& reference, const Color& display); + +private: + virtual void Retranslate() override; + + ManagedPixelSamplerWidget* sampler_widget_; + +}; + +#endif // PIXELSAMPLERPANEL_H diff --git a/app/panel/viewer/viewerbase.cpp b/app/panel/viewer/viewerbase.cpp index ac4f79f83..5918894f4 100644 --- a/app/panel/viewer/viewerbase.cpp +++ b/app/panel/viewer/viewerbase.cpp @@ -45,3 +45,11 @@ VideoRenderBackend *ViewerPanelBase::video_renderer() const { return static_cast(GetTimeBasedWidget())->video_renderer(); } + +void ViewerPanelBase::ConnectPixelSamplerPanel(PixelSamplerPanel *psp) +{ + ViewerWidget* vw = static_cast(GetTimeBasedWidget()); + + connect(psp, &PixelSamplerPanel::visibilityChanged, vw, &ViewerWidget::SetSignalCursorColorEnabled); + connect(vw, &ViewerWidget::CursorColor, psp, &PixelSamplerPanel::SetValues); +} diff --git a/app/panel/viewer/viewerbase.h b/app/panel/viewer/viewerbase.h index d8f1f85d3..d3c3f1c98 100644 --- a/app/panel/viewer/viewerbase.h +++ b/app/panel/viewer/viewerbase.h @@ -1,6 +1,7 @@ #ifndef VIEWERPANELBASE_H #define VIEWERPANELBASE_H +#include "panel/pixelsampler/pixelsamplerpanel.h" #include "panel/timebased/timebased.h" #include "widget/viewer/viewer.h" @@ -24,6 +25,8 @@ public: VideoRenderBackend* video_renderer() const; + void ConnectPixelSamplerPanel(PixelSamplerPanel *psp); + }; #endif // VIEWERPANELBASE_H diff --git a/app/render/CMakeLists.txt b/app/render/CMakeLists.txt index 600d8a1e3..e813dc8c7 100644 --- a/app/render/CMakeLists.txt +++ b/app/render/CMakeLists.txt @@ -20,6 +20,8 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} render/audioparams.h render/audioparams.cpp + render/color.h + render/color.cpp render/colormanager.h render/colormanager.cpp render/colorprocessor.h diff --git a/app/render/backend/opengl/openglframebuffer.cpp b/app/render/backend/opengl/openglframebuffer.cpp index 1de405420..21adfa94f 100644 --- a/app/render/backend/opengl/openglframebuffer.cpp +++ b/app/render/backend/opengl/openglframebuffer.cpp @@ -87,7 +87,7 @@ void OpenGLFramebuffer::Release() context_->functions()->glBindFramebuffer(GL_FRAMEBUFFER, 0); } -void OpenGLFramebuffer::Attach(OpenGLTexturePtr texture, bool clear) +void OpenGLFramebuffer::Attach(OpenGLTexture *texture, bool clear) { if (context_ == nullptr) { return; @@ -115,6 +115,11 @@ void OpenGLFramebuffer::Attach(OpenGLTexturePtr texture, bool clear) f->glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void OpenGLFramebuffer::Attach(OpenGLTexturePtr texture, bool clear) +{ + Attach(texture.get(), clear); +} + void OpenGLFramebuffer::Detach() { if (context_ == nullptr) { diff --git a/app/render/backend/opengl/openglframebuffer.h b/app/render/backend/opengl/openglframebuffer.h index 7f109232d..c39a944cd 100644 --- a/app/render/backend/opengl/openglframebuffer.h +++ b/app/render/backend/opengl/openglframebuffer.h @@ -43,6 +43,7 @@ public: void Release(); + void Attach(OpenGLTexture* texture, bool clear = false); void Attach(OpenGLTexturePtr texture, bool clear = false); void Detach(); @@ -57,7 +58,7 @@ private: GLuint buffer_; - OpenGLTexturePtr texture_; + OpenGLTexture* texture_; }; #endif // OPENGLFRAMEBUFFER_H diff --git a/app/render/color.cpp b/app/render/color.cpp new file mode 100644 index 000000000..3ad4f25c2 --- /dev/null +++ b/app/render/color.cpp @@ -0,0 +1,14 @@ +#include "color.h" + +Color::Color(const char *data, const PixelFormat::Format &format) +{ + OIIO::convert_type(PixelFormat::GetOIIOTypeDesc(format), + data, + PixelFormat::GetOIIOTypeDesc(PixelFormat::PIX_FMT_RGB32F), + data_, + PixelFormat::FormatHasAlphaChannel(format) ? kRGBAChannels : kRGBChannels); + + if (!PixelFormat::FormatHasAlphaChannel(format)) { + set_alpha(1.0f); + } +} diff --git a/app/render/color.h b/app/render/color.h new file mode 100644 index 000000000..fec812237 --- /dev/null +++ b/app/render/color.h @@ -0,0 +1,50 @@ +#ifndef COLOR_H +#define COLOR_H + +#include "common/define.h" +#include "render/pixelformat.h" + +/** + * @brief High precision 32-bit float based RGBA color value + */ +class Color +{ +public: + Color() + { + for (int i=0;iapply(img); } +Color ColorProcessor::ConvertColor(Color in) +{ + processor->applyRGBA(in.data()); + return in; +} + ColorProcessorPtr ColorProcessor::Create(OCIO::ConstConfigRcPtr config, const QString& source_space, const QString& dest_space) { return std::make_shared(config, source_space, dest_space); diff --git a/app/render/colorprocessor.h b/app/render/colorprocessor.h index df1d5d971..47e91e18f 100644 --- a/app/render/colorprocessor.h +++ b/app/render/colorprocessor.h @@ -6,7 +6,7 @@ namespace OCIO = OCIO_NAMESPACE::v1; #include "codec/frame.h" #include "common/constructors.h" - +#include "render/color.h" class ColorProcessor; using ColorProcessorPtr = std::shared_ptr; @@ -35,6 +35,8 @@ public: void ConvertFrame(FramePtr f); + Color ConvertColor(Color in); + private: OCIO::ConstProcessorRcPtr processor; diff --git a/app/render/pixelformat.cpp b/app/render/pixelformat.cpp index 21221a48b..26f5cc5ae 100644 --- a/app/render/pixelformat.cpp +++ b/app/render/pixelformat.cpp @@ -140,50 +140,6 @@ PixelFormat::Format PixelFormat::OIIOFormatToOliveFormat(OIIO::TypeDesc desc, bo return PixelFormat::PIX_FMT_INVALID; } -/*PixelFormat::Info PixelFormat::GetPixelFormatInfo(const PixelFormat::Format &format) -{ - PixelFormat::Info info; - - switch (format) { - case PixelFormat::PIX_FMT_RGB8: - case PixelFormat::PIX_FMT_RGBA8: - info.name = tr("8-bit"); - info.internal_format = (format == PixelFormat::PIX_FMT_RGB8) ? GL_RGB8 : GL_RGBA8; - info.gl_pixel_type = GL_UNSIGNED_BYTE; - info.oiio_desc = OIIO::TypeDesc::UINT8; - break; - case PixelFormat::PIX_FMT_RGB16U: - case PixelFormat::PIX_FMT_RGBA16U: - info.name = tr("16-bit Integer"); - info.internal_format = (format == PixelFormat::PIX_FMT_RGB16U) ? GL_RGB8 : GL_RGBA16; - info.gl_pixel_type = GL_UNSIGNED_SHORT; - info.oiio_desc = OIIO::TypeDesc::UINT16; - break; - case PixelFormat::PIX_FMT_RGB16F: - case PixelFormat::PIX_FMT_RGBA16F: - info.name = tr("Half-Float (16-bit)"); - info.internal_format = (format == PixelFormat::PIX_FMT_RGB8) ? GL_RGB8 : GL_RGBA16F; - info.gl_pixel_type = GL_HALF_FLOAT; - info.oiio_desc = OIIO::TypeDesc::HALF; - break; - case PixelFormat::PIX_FMT_RGB32F: - case PixelFormat::PIX_FMT_RGBA32F: - info.name = tr("Full-Float (32-bit)"); - info.internal_format = (format == PixelFormat::PIX_FMT_RGB8) ? GL_RGB8 : GL_RGBA32F; - info.gl_pixel_type = GL_FLOAT; - info.oiio_desc = OIIO::TypeDesc::FLOAT; - break; - case PixelFormat::PIX_FMT_INVALID: - case PixelFormat::PIX_FMT_COUNT: - qFatal("Invalid pixel format requested"); - } - - info.pixel_format = GL_RGBA; - info.bytes_per_pixel = BytesPerPixel(format); - - return info; -}*/ - int PixelFormat::GetBufferSize(const PixelFormat::Format &format, const int &width, const int &height) { return BytesPerPixel(format) * width * height; diff --git a/app/widget/viewer/CMakeLists.txt b/app/widget/viewer/CMakeLists.txt index 16693f4de..44bcbbb54 100644 --- a/app/widget/viewer/CMakeLists.txt +++ b/app/widget/viewer/CMakeLists.txt @@ -20,6 +20,8 @@ set(OLIVE_SOURCES widget/viewer/audiowaveformview.cpp widget/viewer/footageviewer.h widget/viewer/footageviewer.cpp + widget/viewer/pixelsamplerwidget.h + widget/viewer/pixelsamplerwidget.cpp widget/viewer/viewer.h widget/viewer/viewer.cpp widget/viewer/viewerglwidget.h diff --git a/app/widget/viewer/pixelsamplerwidget.cpp b/app/widget/viewer/pixelsamplerwidget.cpp new file mode 100644 index 000000000..2a630167d --- /dev/null +++ b/app/widget/viewer/pixelsamplerwidget.cpp @@ -0,0 +1,55 @@ +#include "pixelsamplerwidget.h" + +#include + +PixelSamplerWidget::PixelSamplerWidget(QWidget *parent) : + QGroupBox(parent) +{ + QVBoxLayout* layout = new QVBoxLayout(this); + + label_ = new QLabel(); + layout->addWidget(label_); + + setTitle(tr("Color")); + + UpdateLabelInternal(); +} + +void PixelSamplerWidget::SetValues(const Color &color) +{ + color_ = color; + UpdateLabelInternal(); +} + +void PixelSamplerWidget::UpdateLabelInternal() +{ + label_->setText(tr("" + "R: %1
" + "G: %2
" + "B: %3
" + "A: %4" + "").arg(QString::number(color_.red()), + QString::number(color_.green()), + QString::number(color_.blue()), + QString::number(color_.alpha()))); +} + +ManagedPixelSamplerWidget::ManagedPixelSamplerWidget(QWidget *parent) : + QWidget(parent) +{ + QVBoxLayout* layout = new QVBoxLayout(this); + + display_view_ = new PixelSamplerWidget(); + display_view_->setTitle(tr("Display")); + layout->addWidget(display_view_); + + reference_view_ = new PixelSamplerWidget(); + reference_view_->setTitle(tr("Reference")); + layout->addWidget(reference_view_); +} + +void ManagedPixelSamplerWidget::SetValues(const Color &reference, const Color &display) +{ + reference_view_->SetValues(reference); + display_view_->SetValues(display); +} diff --git a/app/widget/viewer/pixelsamplerwidget.h b/app/widget/viewer/pixelsamplerwidget.h new file mode 100644 index 000000000..e3a037dc5 --- /dev/null +++ b/app/widget/viewer/pixelsamplerwidget.h @@ -0,0 +1,44 @@ +#ifndef PIXELSAMPLERWIDGET_H +#define PIXELSAMPLERWIDGET_H + +#include +#include +#include + +#include "render/color.h" + +class PixelSamplerWidget : public QGroupBox +{ + Q_OBJECT +public: + PixelSamplerWidget(QWidget* parent = nullptr); + +public slots: + void SetValues(const Color& color); + +private: + void UpdateLabelInternal(); + + Color color_; + + QLabel* label_; + +}; + +class ManagedPixelSamplerWidget : public QWidget +{ + Q_OBJECT +public: + ManagedPixelSamplerWidget(QWidget* parent = nullptr); + +public slots: + void SetValues(const Color& reference, const Color& display); + +private: + PixelSamplerWidget* reference_view_; + + PixelSamplerWidget* display_view_; + +}; + +#endif // PIXELSAMPLERWIDGET_H diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index c517b13a5..d1f855a2a 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -57,6 +57,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : gl_widget_ = new ViewerGLWidget(); connect(gl_widget_, &ViewerGLWidget::customContextMenuRequested, this, &ViewerWidget::ShowContextMenu); + connect(gl_widget_, &ViewerGLWidget::CursorColor, this, &ViewerWidget::CursorColor); connect(sizer_, &ViewerSizer::RequestMatrix, gl_widget_, &ViewerGLWidget::SetMatrix); sizer_->SetWidget(gl_widget_); @@ -531,6 +532,11 @@ void ViewerWidget::SetOCIOLook(const QString &look) gl_widget_->SetOCIOLook(look); } +void ViewerWidget::SetSignalCursorColorEnabled(bool e) +{ + gl_widget_->SetSignalCursorColorEnabled(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 272a93645..87a817966 100644 --- a/app/widget/viewer/viewer.h +++ b/app/widget/viewer/viewer.h @@ -106,6 +106,17 @@ public slots: */ void SetOCIOLook(const QString& look); + /** + * @brief Wrapper for ViewerGLWidget::SetSignalCursorColorEnabled() + */ + void SetSignalCursorColorEnabled(bool e); + +signals: + /** + * @brief Wrapper for ViewerGLWidget::CursorColor() + */ + void CursorColor(const Color& reference, const Color& display); + protected: virtual void TimebaseChangedEvent(const rational &) override; virtual void TimeChangedEvent(const int64_t &) override; diff --git a/app/widget/viewer/viewerglwidget.cpp b/app/widget/viewer/viewerglwidget.cpp index 8dc05e027..c2b1f5db1 100644 --- a/app/widget/viewer/viewerglwidget.cpp +++ b/app/widget/viewer/viewerglwidget.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -39,7 +40,8 @@ bool ViewerGLWidget::nouveau_check_done_ = false; ViewerGLWidget::ViewerGLWidget(QWidget *parent) : QOpenGLWidget(parent), color_manager_(nullptr), - has_image_(false) + has_image_(false), + signal_cursor_color_(false) { setContextMenuPolicy(Qt::CustomContextMenu); } @@ -128,6 +130,25 @@ void ViewerGLWidget::SetImage(const QString &fn) update(); } +void ViewerGLWidget::SetSignalCursorColorEnabled(bool e) +{ + qDebug() << e; + + signal_cursor_color_ = e; + setMouseTracking(e); + + // Create frame buffer for reading from texture + if (e != frame_buffer_.IsCreated()) { + makeCurrent(); + if (e) { + frame_buffer_.Create(context()); + } else { + frame_buffer_.Destroy(); + } + doneCurrent(); + } +} + void ViewerGLWidget::SetOCIODisplay(const QString &display) { ocio_display_ = display; @@ -184,6 +205,31 @@ void ViewerGLWidget::mousePressEvent(QMouseEvent *event) emit DragStarted(); } +void ViewerGLWidget::mouseMoveEvent(QMouseEvent *event) +{ + QOpenGLWidget::mouseMoveEvent(event); + + if (signal_cursor_color_) { + Color reference, display; + + if (has_image_) { + QVector3D pixel_pos(static_cast(event->x()) / static_cast(width()) * 2.0f - 1.0f, + static_cast(event->y()) / static_cast(height()) * 2.0f - 1.0f, + 0); + + pixel_pos = pixel_pos * matrix_.inverted(); + + int frame_x = qRound((pixel_pos.x() + 1.0f) * 0.5f * load_buffer_.width()); + int frame_y = qRound((pixel_pos.y() + 1.0f) * 0.5f * load_buffer_.height()); + + reference = load_buffer_.get_pixel(frame_x, frame_y); + display = color_service_->ConvertColor(reference); + } + + emit CursorColor(reference, display); + } +} + void ViewerGLWidget::SetOCIOParameters(const QString &display, const QString &view, const QString &look) { ocio_display_ = display; diff --git a/app/widget/viewer/viewerglwidget.h b/app/widget/viewer/viewerglwidget.h index 4c14fb701..2110b236e 100644 --- a/app/widget/viewer/viewerglwidget.h +++ b/app/widget/viewer/viewerglwidget.h @@ -24,8 +24,10 @@ #include #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 "render/color.h" #include "render/colormanager.h" /** @@ -119,15 +121,37 @@ public slots: */ void SetMatrix(const QMatrix4x4& mat); + /** + * @brief Enables or disables whether this color at the cursor should be emitted + * + * Since tracking the mouse every movement, reading pixels, and doing color transforms are processor intensive, we + * have an option for it. Ideally, this should be connected to a PixelSamplerPanel::visibilityChanged signal so that + * it can automatically be enabled when the user is pixel sampling and disabled for optimization when they're not. + */ + void SetSignalCursorColorEnabled(bool e); + signals: + /** + * @brief Signal emitted when the user starts dragging from the viewer + */ void DragStarted(); + /** + * @brief Signal emitted when cursor color is enabled and the user's mouse position changes + */ + void CursorColor(const Color& reference, const Color& display); + protected: /** * @brief Override the mouse press event simply to emit the DragStarted() signal */ virtual void mousePressEvent(QMouseEvent* event) override; + /** + * @brief Override mouse move to provide functionality for + */ + virtual void mouseMoveEvent(QMouseEvent* event) override; + /** * @brief Initialize function to set up the OpenGL context upon its construction * @@ -183,6 +207,11 @@ private: */ OpenGLColorProcessorPtr color_service_; + /** + * @brief Framebuffer used for reading reference space pixels from the texture + */ + OpenGLFramebuffer frame_buffer_; + /** * @brief Drawing matrix (defaults to identity) */ @@ -199,6 +228,8 @@ private: bool has_image_; + bool signal_cursor_color_; + private slots: /** * @brief Slot to connect just before the OpenGL context is destroyed to clean up resources diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index dfce3dc10..26074e0b5 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -68,6 +68,8 @@ MainWindow::MainWindow(QWidget *parent) : footage_viewer_panel_->raise(); sequence_viewer_panel_ = PanelManager::instance()->CreatePanel(this); addDockWidget(Qt::TopDockWidgetArea, sequence_viewer_panel_); + pixel_sampler_panel_ = PanelManager::instance()->CreatePanel(this); + addDockWidget(Qt::TopDockWidgetArea, pixel_sampler_panel_); project_panel_ = PanelManager::instance()->CreatePanel(this); addDockWidget(Qt::BottomDockWidgetArea, project_panel_); tool_panel_ = PanelManager::instance()->CreatePanel(this); @@ -97,6 +99,9 @@ MainWindow::MainWindow(QWidget *parent) : sequence_viewer_panel_->ConnectTimeBasedPanel(param_panel_); sequence_viewer_panel_->ConnectTimeBasedPanel(curve_panel_); + footage_viewer_panel_->ConnectPixelSamplerPanel(pixel_sampler_panel_); + sequence_viewer_panel_->ConnectPixelSamplerPanel(pixel_sampler_panel_); + connect(project_panel_, &ProjectPanel::ProjectNameChanged, this, &MainWindow::UpdateTitle); UpdateTitle(); } @@ -303,6 +308,8 @@ void MainWindow::SetDefaultLayout() task_man_panel_->setFloating(true); curve_panel_->close(); curve_panel_->setFloating(true); + pixel_sampler_panel_->close(); + pixel_sampler_panel_->setFloating(true); resizeDocks({node_panel_, param_panel_, sequence_viewer_panel_}, {width()/3, width()/3, width()/3}, diff --git a/app/window/mainwindow/mainwindow.h b/app/window/mainwindow/mainwindow.h index d0aba602a..f57550db8 100644 --- a/app/window/mainwindow/mainwindow.h +++ b/app/window/mainwindow/mainwindow.h @@ -34,6 +34,7 @@ #include "panel/tool/tool.h" #include "panel/footageviewer/footageviewer.h" #include "panel/sequenceviewer/sequenceviewer.h" +#include "panel/pixelsampler/pixelsamplerpanel.h" #include "project/project.h" /** @@ -76,6 +77,7 @@ private: AudioMonitorPanel* audio_monitor_panel_; TaskManagerPanel* task_man_panel_; CurvePanel* curve_panel_; + PixelSamplerPanel* pixel_sampler_panel_; private slots: void FocusedPanelChanged(PanelWidget* panel);