From 2174100342cd6b90fd532517017c73f0e70a37bb Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 1 Jun 2020 17:45:47 +0100 Subject: [PATCH 01/16] Add basic tranlation functionality to the viewer Had to separate zoom and translate matrices to stop the zoom being applied to itelf. This also required adding separate get/set functions for each matrix and a GetcombinedMatrix() funtion. Added those functions ot other files where needed ut may be wrong. Need to look at export.cpp Also changed the mouse move and press events to make translation work. --- app/widget/viewer/viewer.cpp | 6 ++-- app/widget/viewer/viewerdisplay.cpp | 52 ++++++++++++++++++++++++++--- app/widget/viewer/viewerdisplay.h | 13 ++++++-- app/widget/viewer/viewerwindow.cpp | 2 +- 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 6280ad88f..17b5ac8c7 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -78,7 +78,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(display_widget_, &ViewerDisplayWidget::CursorColor, this, &ViewerWidget::CursorColor); connect(display_widget_, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged); connect(display_widget_, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged); - connect(sizer_, &ViewerSizer::RequestMatrix, display_widget_, &ViewerDisplayWidget::SetMatrix); + connect(sizer_, &ViewerSizer::RequestMatrix, display_widget_, &ViewerDisplayWidget::SetMatrixZoom); sizer_->SetWidget(display_widget_); // Create waveform view when audio is connected and video isn't @@ -322,9 +322,9 @@ void ViewerWidget::SetOverrideSize(int width, int height) void ViewerWidget::SetMatrix(const QMatrix4x4 &mat) { - display_widget_->SetMatrix(mat); + display_widget_->SetMatrixZoom(mat); foreach (ViewerWindow* vw, windows_) { - vw->display_widget()->SetMatrix(mat); + vw->display_widget()->SetMatrixZoom(mat); } } diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 420eaf423..d55484aa8 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -56,12 +56,24 @@ ViewerDisplayWidget::~ViewerDisplayWidget() ContextCleanup(); } -void ViewerDisplayWidget::SetMatrix(const QMatrix4x4 &mat) +void ViewerDisplayWidget::SetMatrixTranslate(const QMatrix4x4 &mat) { - matrix_ = mat; + translate_matrix_ = mat; update(); } +void ViewerDisplayWidget::SetMatrixZoom(const QMatrix4x4 &mat) +{ + scale_matrix_ = mat; + update(); +} + +QMatrix4x4 ViewerDisplayWidget::GetCompleteMatrix() +{ + QMatrix4x4 mat; + return scale_matrix_ * translate_matrix_ * mat; +} + void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e) { signal_cursor_color_ = e; @@ -145,6 +157,13 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) return; } + if (event->button() == Qt::MiddleButton) { + printf("Middle Button Clicked\n"); + position_ = event->pos(); + printf("x: %d, y:%d\n", position_.x(), position_.y()); + return; + } + QOpenGLWidget::mousePressEvent(event); if (event->button() == Qt::LeftButton) { @@ -154,6 +173,23 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { + if (event->buttons() & Qt::MiddleButton) { + printf("Move\n"); + QPointF delta = event->pos() - position_; + delta.setX(delta.x() / width()); + delta.setY(delta.y() / height()); + //this->move(this->pos()+new_position); + //QPoint new_pos = this->pos() + delta; + QMatrix4x4 mat; + //mat.translate(static_cast(new_pos.x()) / width(), static_cast(-1 * new_pos.y()) / height()); + printf("x: %f, y:%f\n", delta.x(), delta.y()); + mat = GetMatrixTranslate(); + mat.translate(delta.x(), -1.0f * delta.y()); + SetMatrixTranslate(mat); + position_ = event-> pos(); + return; + } + if (gizmo_click_) { gizmos_->GizmoMove(event->pos(), QVector2D(GetTexturePosition(size())), gizmo_drag_time_); return; @@ -169,7 +205,7 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) static_cast(event->y()) / static_cast(height()) * 2.0f - 1.0f, 0); - pixel_pos = pixel_pos * matrix_.inverted(); + pixel_pos = pixel_pos * GetCompleteMatrix().inverted(); int frame_x = qRound((pixel_pos.x() + 1.0f) * 0.5f * last_loaded_buffer_->width()); int frame_y = qRound((pixel_pos.y() + 1.0f) * 0.5f * last_loaded_buffer_->height()); @@ -194,6 +230,11 @@ void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event) QOpenGLWidget::mouseReleaseEvent(event); } +QMatrix4x4 ViewerDisplayWidget::GetMatrixTranslate() +{ + return translate_matrix_; +} + void ViewerDisplayWidget::initializeGL() { ManagedDisplayWidget::initializeGL(); @@ -231,8 +272,11 @@ void ViewerDisplayWidget::paintGL() // Bind retrieved texture f->glBindTexture(GL_TEXTURE_2D, texture_.texture()); + //QMatrix4x4 mat; + //mat = scale_matrix_ * translate_matrix_ * mat; + // Blit using the color service - color_service()->ProcessOpenGL(true, matrix_); + color_service()->ProcessOpenGL(true, GetCompleteMatrix()); // Release retrieved texture f->glBindTexture(GL_TEXTURE_2D, 0); diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 5f18cc303..71c804e84 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -66,7 +66,9 @@ public: virtual ~ViewerDisplayWidget() override; - const QMatrix4x4& GetMatrix(); + QMatrix4x4 GetMatrixTranslate(); + + QMatrix4x4 GetCompleteMatrix(); const ViewerSafeMarginInfo& GetSafeMargin() const; void SetSafeMargins(const ViewerSafeMarginInfo& safe_margin); @@ -83,7 +85,8 @@ public slots: * * Set this if you want the drawing to pass through some sort of transform (most of the time you won't want this). */ - void SetMatrix(const QMatrix4x4& mat); + void SetMatrixTranslate(const QMatrix4x4& mat); + void SetMatrixZoom(const QMatrix4x4& mat); /** * @brief Enables or disables whether this color at the cursor should be emitted @@ -158,7 +161,9 @@ private: /** * @brief Drawing matrix (defaults to identity) */ - QMatrix4x4 matrix_; + QMatrix4x4 translate_matrix_; + + QMatrix4x4 scale_matrix_; #ifdef Q_OS_LINUX static bool nouveau_check_done_; @@ -178,6 +183,8 @@ private: FramePtr last_loaded_buffer_; + QPoint position_; + private slots: /** * @brief Slot to connect just before the OpenGL context is destroyed to clean up resources diff --git a/app/widget/viewer/viewerwindow.cpp b/app/widget/viewer/viewerwindow.cpp index 983d4289b..dc505914d 100644 --- a/app/widget/viewer/viewerwindow.cpp +++ b/app/widget/viewer/viewerwindow.cpp @@ -59,7 +59,7 @@ void ViewerWindow::SetResolution(int width, int height) mat.scale(1.0f, window_ar / image_ar, 1.0f); } - display_widget_->SetMatrix(mat); + display_widget_->SetMatrixZoom(mat); } void ViewerWindow::Play(const int64_t& start_timestamp, const int& playback_speed, const rational &timebase) From f4d56f79cb27632b9831c10500d4f06e671169b0 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 1 Jun 2020 17:59:04 +0100 Subject: [PATCH 02/16] Add ability to reset translation to center --- app/widget/viewer/viewerdisplay.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index d55484aa8..9d3ff22f5 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -157,6 +157,12 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) return; } + // reset translation + if (event->button() == Qt::MiddleButton && event->modifiers() & Qt::ControlModifier) { + QMatrix4x4 mat; + SetMatrixTranslate(mat); + } + if (event->button() == Qt::MiddleButton) { printf("Middle Button Clicked\n"); position_ = event->pos(); From 92eadc685459da53d0178026c171d5f2d2627e82 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 1 Jun 2020 18:10:33 +0100 Subject: [PATCH 03/16] Cleanup --- app/widget/viewer/viewerdisplay.cpp | 16 ++++++---------- app/widget/viewer/viewerdisplay.h | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 9d3ff22f5..b438a4414 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -163,10 +163,9 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) SetMatrixTranslate(mat); } + // get current position in preperation for move event if (event->button() == Qt::MiddleButton) { - printf("Middle Button Clicked\n"); position_ = event->pos(); - printf("x: %d, y:%d\n", position_.x(), position_.y()); return; } @@ -180,18 +179,18 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::MiddleButton) { - printf("Move\n"); QPointF delta = event->pos() - position_; + // scale delta to widget size delta.setX(delta.x() / width()); delta.setY(delta.y() / height()); - //this->move(this->pos()+new_position); - //QPoint new_pos = this->pos() + delta; + QMatrix4x4 mat; - //mat.translate(static_cast(new_pos.x()) / width(), static_cast(-1 * new_pos.y()) / height()); - printf("x: %f, y:%f\n", delta.x(), delta.y()); mat = GetMatrixTranslate(); + // Have to invert y axis, possibly because of something in the OpenGL code? mat.translate(delta.x(), -1.0f * delta.y()); SetMatrixTranslate(mat); + + // get new start position position_ = event-> pos(); return; } @@ -278,9 +277,6 @@ void ViewerDisplayWidget::paintGL() // Bind retrieved texture f->glBindTexture(GL_TEXTURE_2D, texture_.texture()); - //QMatrix4x4 mat; - //mat = scale_matrix_ * translate_matrix_ * mat; - // Blit using the color service color_service()->ProcessOpenGL(true, GetCompleteMatrix()); diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 71c804e84..a1f8cec66 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -66,8 +66,15 @@ public: virtual ~ViewerDisplayWidget() override; + /** + * @brief Return the translation only matrix. + */ QMatrix4x4 GetMatrixTranslate(); + /** + * @brief Return the complete translation and scale matrix + * This must be used if you want the entire transformation pipeline (scale and translate). + */ QMatrix4x4 GetCompleteMatrix(); const ViewerSafeMarginInfo& GetSafeMargin() const; @@ -86,6 +93,10 @@ public slots: * Set this if you want the drawing to pass through some sort of transform (most of the time you won't want this). */ void SetMatrixTranslate(const QMatrix4x4& mat); + + /** + * @brief Set the scale matrix. + */ void SetMatrixZoom(const QMatrix4x4& mat); /** @@ -159,10 +170,13 @@ private: OpenGLTexture texture_; /** - * @brief Drawing matrix (defaults to identity) + * @brief Translation only matrix (defaults to identity). */ QMatrix4x4 translate_matrix_; + /** + * @breif Scale only matrix. + */ QMatrix4x4 scale_matrix_; #ifdef Q_OS_LINUX @@ -183,6 +197,9 @@ private: FramePtr last_loaded_buffer_; + /** + * @brief position of mouse to calculate delta from. + */ QPoint position_; private slots: From f6c70f583f69e7364056b67f92f756ab540e0fb5 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 1 Jun 2020 19:11:33 +0100 Subject: [PATCH 04/16] Panning now only works if the viewier is zoomed --- app/widget/viewer/viewer.cpp | 1 + app/widget/viewer/viewerdisplay.cpp | 17 ++++++++++++++--- app/widget/viewer/viewerdisplay.h | 4 ++++ app/widget/viewer/viewersizer.cpp | 3 ++- app/widget/viewer/viewersizer.h | 1 + 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index 17b5ac8c7..a90c7242d 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -79,6 +79,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(display_widget_, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged); connect(display_widget_, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged); connect(sizer_, &ViewerSizer::RequestMatrix, display_widget_, &ViewerDisplayWidget::SetMatrixZoom); + connect(sizer_, &ViewerSizer::SetZoomFlag, display_widget_, &ViewerDisplayWidget::SetZoomFlag); sizer_->SetWidget(display_widget_); // Create waveform view when audio is connected and video isn't diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index b438a4414..1228530de 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -47,7 +47,8 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : signal_cursor_color_(false), gizmos_(nullptr), gizmo_click_(false), - last_loaded_buffer_(nullptr) + last_loaded_buffer_(nullptr), + zoomed_(false) { } @@ -68,6 +69,16 @@ void ViewerDisplayWidget::SetMatrixZoom(const QMatrix4x4 &mat) update(); } +void ViewerDisplayWidget::SetZoomFlag(bool flag) +{ + zoomed_ = flag; + // If not scaled reset translation matrix to identity + if (!flag) { + QMatrix4x4 mat; + SetMatrixTranslate(mat); + } +} + QMatrix4x4 ViewerDisplayWidget::GetCompleteMatrix() { QMatrix4x4 mat; @@ -164,7 +175,7 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) } // get current position in preperation for move event - if (event->button() == Qt::MiddleButton) { + if (event->button() == Qt::MiddleButton && zoomed_) { position_ = event->pos(); return; } @@ -178,7 +189,7 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { - if (event->buttons() & Qt::MiddleButton) { + if (event->buttons() & Qt::MiddleButton && zoomed_) { QPointF delta = event->pos() - position_; // scale delta to widget size delta.setX(delta.x() / width()); diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index a1f8cec66..4d98af1ce 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -116,6 +116,8 @@ public slots: */ void SetImage(FramePtr in_buffer); + void SetZoomFlag(bool flag); + signals: /** * @brief Signal emitted when the user starts dragging from the viewer @@ -179,6 +181,8 @@ private: */ QMatrix4x4 scale_matrix_; + bool zoomed_; + #ifdef Q_OS_LINUX static bool nouveau_check_done_; #endif diff --git a/app/widget/viewer/viewersizer.cpp b/app/widget/viewer/viewersizer.cpp index 8f492d488..0780f3c58 100644 --- a/app/widget/viewer/viewersizer.cpp +++ b/app/widget/viewer/viewersizer.cpp @@ -105,6 +105,7 @@ void ViewerSizer::UpdateSize() // This container is taller than the image, scale by width child_size = QSize(width(), qRound(child_size.width() / aspect_ratio_)); } + emit SetZoomFlag(false); } else { @@ -128,7 +129,7 @@ void ViewerSizer::UpdateSize() child_matrix.scale(x_scale, y_scale, 1.0F); child_size = QSize(zoomed_width, zoomed_height); - + emit SetZoomFlag(true); } widget_->resize(child_size); diff --git a/app/widget/viewer/viewersizer.h b/app/widget/viewer/viewersizer.h index 2363f28cf..6728018a6 100644 --- a/app/widget/viewer/viewersizer.h +++ b/app/widget/viewer/viewersizer.h @@ -65,6 +65,7 @@ public: signals: void RequestMatrix(const QMatrix4x4& matrix); + void SetZoomFlag(bool flag); protected: /** From 7617ddabe32641226bd8439027e4ba99b5433e0a Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 2 Jun 2020 17:27:35 +0100 Subject: [PATCH 05/16] Fix translation bugs The translation needs to be scaled relative to the zoom percentage so we get sensible movement when dragging. Dragging is also disabled when the image is smaller than the container widget. Re-orders the initialisation of some variables to stop a compile warning on Travis. --- app/widget/viewer/viewer.cpp | 2 +- app/widget/viewer/viewerdisplay.cpp | 20 +++++++++++++------- app/widget/viewer/viewerdisplay.h | 14 +++++++++++--- app/widget/viewer/viewersizer.cpp | 9 +++++++-- app/widget/viewer/viewersizer.h | 2 +- 5 files changed, 33 insertions(+), 14 deletions(-) diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index a90c7242d..aa1fe9a07 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -79,7 +79,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(display_widget_, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged); connect(display_widget_, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged); connect(sizer_, &ViewerSizer::RequestMatrix, display_widget_, &ViewerDisplayWidget::SetMatrixZoom); - connect(sizer_, &ViewerSizer::SetZoomFlag, display_widget_, &ViewerDisplayWidget::SetZoomFlag); + connect(sizer_, &ViewerSizer::SendZoomData, display_widget_, &ViewerDisplayWidget::SetZoomData); sizer_->SetWidget(display_widget_); // Create waveform view when audio is connected and video isn't diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 1228530de..f55299ff2 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -48,7 +48,8 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : gizmos_(nullptr), gizmo_click_(false), last_loaded_buffer_(nullptr), - zoomed_(false) + zoomed_(false), + zoom_multiplier_(1.0) { } @@ -69,13 +70,17 @@ void ViewerDisplayWidget::SetMatrixZoom(const QMatrix4x4 &mat) update(); } -void ViewerDisplayWidget::SetZoomFlag(bool flag) +void ViewerDisplayWidget::SetZoomData(bool flag, int percent) { zoomed_ = flag; - // If not scaled reset translation matrix to identity + // If the image is smaller than the conainer widget we disable translation if (!flag) { QMatrix4x4 mat; SetMatrixTranslate(mat); + zoom_multiplier_ = 1.0f; + } + else { + zoom_multiplier_ = 1.0 / (static_cast(percent) * 0.01); } } @@ -174,7 +179,7 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) SetMatrixTranslate(mat); } - // get current position in preperation for move event + // If translation is enabled get current position in preperation for move event if (event->button() == Qt::MiddleButton && zoomed_) { position_ = event->pos(); return; @@ -189,11 +194,12 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { + // Only allow translation if the image is larger than the container widget if (event->buttons() & Qt::MiddleButton && zoomed_) { QPointF delta = event->pos() - position_; - // scale delta to widget size - delta.setX(delta.x() / width()); - delta.setY(delta.y() / height()); + // scale delta to widget size and zoom level + delta.setX(zoom_multiplier_ * delta.x() / width()); + delta.setY(zoom_multiplier_ * delta.y() / height()); QMatrix4x4 mat; mat = GetMatrixTranslate(); diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 4d98af1ce..f6c10a92f 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -116,7 +116,7 @@ public slots: */ void SetImage(FramePtr in_buffer); - void SetZoomFlag(bool flag); + void SetZoomData(bool flag, int percent); signals: /** @@ -181,8 +181,6 @@ private: */ QMatrix4x4 scale_matrix_; - bool zoomed_; - #ifdef Q_OS_LINUX static bool nouveau_check_done_; #endif @@ -201,6 +199,16 @@ private: FramePtr last_loaded_buffer_; + /** + * @brief Tells us if the image is zoomed in to be larger than the container widget. + */ + bool zoomed_; + + /** + * @brief Scale the translation so the image sticks to the mouse and we get sensible movement + */ + double zoom_multiplier_; + /** * @brief position of mouse to calculate delta from. */ diff --git a/app/widget/viewer/viewersizer.cpp b/app/widget/viewer/viewersizer.cpp index 0780f3c58..7cab8239f 100644 --- a/app/widget/viewer/viewersizer.cpp +++ b/app/widget/viewer/viewersizer.cpp @@ -105,12 +105,15 @@ void ViewerSizer::UpdateSize() // This container is taller than the image, scale by width child_size = QSize(width(), qRound(child_size.width() / aspect_ratio_)); } - emit SetZoomFlag(false); + emit SendZoomData(false, 0); } else { float x_scale = 1.0f; float y_scale = 1.0f; + // Translation is only active if the image is bigger then the widget + // See ViewerDisplayWidget::SetZoomData + bool zoomed_in = false; int zoomed_width = qRound(width_ * static_cast(zoom_) * 0.01); int zoomed_height = qRound(height_ * static_cast(zoom_) * 0.01); @@ -118,18 +121,20 @@ void ViewerSizer::UpdateSize() if (zoomed_width > width()) { x_scale = static_cast(zoomed_width) / static_cast(width()); zoomed_width = width(); + zoomed_in = true; } if (zoomed_height > height()) { y_scale = static_cast(zoomed_height) / static_cast(height()); zoomed_height = height(); + zoomed_in = true; } // Rather than make a huge surface, we still crop at our width/height and then signal a matrix child_matrix.scale(x_scale, y_scale, 1.0F); child_size = QSize(zoomed_width, zoomed_height); - emit SetZoomFlag(true); + emit SendZoomData(zoomed_in, zoom_); } widget_->resize(child_size); diff --git a/app/widget/viewer/viewersizer.h b/app/widget/viewer/viewersizer.h index 6728018a6..9c838a834 100644 --- a/app/widget/viewer/viewersizer.h +++ b/app/widget/viewer/viewersizer.h @@ -65,7 +65,7 @@ public: signals: void RequestMatrix(const QMatrix4x4& matrix); - void SetZoomFlag(bool flag); + void SendZoomData(bool flag, int percent); protected: /** From 100da912ad5125bee192f6c5327f53dc3146884f Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 16 Jun 2020 14:41:35 +0100 Subject: [PATCH 06/16] Add hand tool dragging If Hand Tool is selected we can now drag with a left click AS WELL AS middle click. This keeps the view behaviour in line with other widgets in Olive. For simplicity it does not use handmovableview. --- app/widget/viewer/viewerdisplay.cpp | 19 +++++++++++++++++-- app/widget/viewer/viewerdisplay.h | 5 +++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index f55299ff2..96554b1b6 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -35,6 +35,7 @@ #include "render/backend/opengl/openglrenderfunctions.h" #include "render/backend/opengl/openglshader.h" #include "render/pixelformat.h" +#include "core.h" OLIVE_NAMESPACE_ENTER @@ -51,6 +52,9 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : zoomed_(false), zoom_multiplier_(1.0) { + connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::ToolChanged); + + ToolChanged(Core::instance()->tool()); } ViewerDisplayWidget::~ViewerDisplayWidget() @@ -84,6 +88,17 @@ void ViewerDisplayWidget::SetZoomData(bool flag, int percent) } } +void ViewerDisplayWidget::ToolChanged(Tool::Item tool) +{ + if (tool == Tool::kHand) { + hand_tool_ = true; + setCursor(Qt::OpenHandCursor); + } else { + hand_tool_ = false; + unsetCursor(); + } +} + QMatrix4x4 ViewerDisplayWidget::GetCompleteMatrix() { QMatrix4x4 mat; @@ -180,7 +195,7 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) } // If translation is enabled get current position in preperation for move event - if (event->button() == Qt::MiddleButton && zoomed_) { + if ((event->button() == Qt::MiddleButton || hand_tool_) && zoomed_) { position_ = event->pos(); return; } @@ -195,7 +210,7 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { // Only allow translation if the image is larger than the container widget - if (event->buttons() & Qt::MiddleButton && zoomed_) { + if ((event->buttons() & Qt::MiddleButton || hand_tool_) && zoomed_) { QPointF delta = event->pos() - position_; // scale delta to widget size and zoom level delta.setX(zoom_multiplier_ * delta.x() / width()); diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index f6c10a92f..2e10c1392 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -30,6 +30,7 @@ #include "render/backend/opengl/opengltexture.h" #include "render/color.h" #include "render/colormanager.h" +#include "tool/tool.h" #include "viewersafemargininfo.h" #include "widget/manageddisplay/manageddisplay.h" #include "widget/timetarget/timetarget.h" @@ -118,6 +119,8 @@ public slots: void SetZoomData(bool flag, int percent); + void ToolChanged(Tool::Item tool); + signals: /** * @brief Signal emitted when the user starts dragging from the viewer @@ -214,6 +217,8 @@ private: */ QPoint position_; + bool hand_tool_; + private slots: /** * @brief Slot to connect just before the OpenGL context is destroyed to clean up resources From 389f2300508146cb89072985bd5be6abb4e59521 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 16 Jun 2020 16:57:38 +0100 Subject: [PATCH 07/16] Properly fix translation errors in viewer Original fix was wrong, this sorts it out I think. Delta values had to be doubled as we're in Clip space (I think) and the matrix multiplication order had to be swapped around. Updated one of the signla/slot pairs to be simpler as we no longer need to pass the zoom percentage back and forth. --- app/widget/viewer/viewer.cpp | 2 +- app/widget/viewer/viewerdisplay.cpp | 19 +++++++------------ app/widget/viewer/viewerdisplay.h | 7 +------ app/widget/viewer/viewersizer.cpp | 4 ++-- app/widget/viewer/viewersizer.h | 2 +- 5 files changed, 12 insertions(+), 22 deletions(-) diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index aa1fe9a07..5ba79da92 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -79,7 +79,7 @@ ViewerWidget::ViewerWidget(QWidget *parent) : connect(display_widget_, &ViewerDisplayWidget::ColorProcessorChanged, this, &ViewerWidget::ColorProcessorChanged); connect(display_widget_, &ViewerDisplayWidget::ColorManagerChanged, this, &ViewerWidget::ColorManagerChanged); connect(sizer_, &ViewerSizer::RequestMatrix, display_widget_, &ViewerDisplayWidget::SetMatrixZoom); - connect(sizer_, &ViewerSizer::SendZoomData, display_widget_, &ViewerDisplayWidget::SetZoomData); + connect(sizer_, &ViewerSizer::IsZoomed, display_widget_, &ViewerDisplayWidget::IsZoomed); sizer_->SetWidget(display_widget_); // Create waveform view when audio is connected and video isn't diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 96554b1b6..e9cebbe34 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -49,8 +49,7 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : gizmos_(nullptr), gizmo_click_(false), last_loaded_buffer_(nullptr), - zoomed_(false), - zoom_multiplier_(1.0) + zoomed_(false) { connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::ToolChanged); @@ -74,17 +73,13 @@ void ViewerDisplayWidget::SetMatrixZoom(const QMatrix4x4 &mat) update(); } -void ViewerDisplayWidget::SetZoomData(bool flag, int percent) +void ViewerDisplayWidget::IsZoomed(bool flag) { zoomed_ = flag; - // If the image is smaller than the conainer widget we disable translation + // If the image is smaller than the container widget we disable translation if (!flag) { QMatrix4x4 mat; SetMatrixTranslate(mat); - zoom_multiplier_ = 1.0f; - } - else { - zoom_multiplier_ = 1.0 / (static_cast(percent) * 0.01); } } @@ -102,7 +97,7 @@ void ViewerDisplayWidget::ToolChanged(Tool::Item tool) QMatrix4x4 ViewerDisplayWidget::GetCompleteMatrix() { QMatrix4x4 mat; - return scale_matrix_ * translate_matrix_ * mat; + return translate_matrix_ * scale_matrix_ * mat; } void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e) @@ -212,9 +207,9 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) // Only allow translation if the image is larger than the container widget if ((event->buttons() & Qt::MiddleButton || hand_tool_) && zoomed_) { QPointF delta = event->pos() - position_; - // scale delta to widget size and zoom level - delta.setX(zoom_multiplier_ * delta.x() / width()); - delta.setY(zoom_multiplier_ * delta.y() / height()); + // scale delta to widget size + delta.setX(2 * delta.x() / width()); + delta.setY(2 * delta.y() / height()); QMatrix4x4 mat; mat = GetMatrixTranslate(); diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 2e10c1392..a43e58804 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -117,7 +117,7 @@ public slots: */ void SetImage(FramePtr in_buffer); - void SetZoomData(bool flag, int percent); + void IsZoomed(bool flag); void ToolChanged(Tool::Item tool); @@ -207,11 +207,6 @@ private: */ bool zoomed_; - /** - * @brief Scale the translation so the image sticks to the mouse and we get sensible movement - */ - double zoom_multiplier_; - /** * @brief position of mouse to calculate delta from. */ diff --git a/app/widget/viewer/viewersizer.cpp b/app/widget/viewer/viewersizer.cpp index 7cab8239f..99876cab2 100644 --- a/app/widget/viewer/viewersizer.cpp +++ b/app/widget/viewer/viewersizer.cpp @@ -105,7 +105,7 @@ void ViewerSizer::UpdateSize() // This container is taller than the image, scale by width child_size = QSize(width(), qRound(child_size.width() / aspect_ratio_)); } - emit SendZoomData(false, 0); + emit IsZoomed(false); } else { @@ -134,7 +134,7 @@ void ViewerSizer::UpdateSize() child_matrix.scale(x_scale, y_scale, 1.0F); child_size = QSize(zoomed_width, zoomed_height); - emit SendZoomData(zoomed_in, zoom_); + emit IsZoomed(zoomed_in); } widget_->resize(child_size); diff --git a/app/widget/viewer/viewersizer.h b/app/widget/viewer/viewersizer.h index 9c838a834..3948e2e8f 100644 --- a/app/widget/viewer/viewersizer.h +++ b/app/widget/viewer/viewersizer.h @@ -65,7 +65,7 @@ public: signals: void RequestMatrix(const QMatrix4x4& matrix); - void SendZoomData(bool flag, int percent); + void IsZoomed(bool flag); protected: /** From 7665e9e24096320450a878985066707de5403bef Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Tue, 16 Jun 2020 17:15:21 +0100 Subject: [PATCH 08/16] Update comments. --- app/widget/viewer/viewerdisplay.cpp | 13 +++++++------ app/widget/viewer/viewerdisplay.h | 14 +++++++++++++- app/widget/viewer/viewersizer.h | 4 ++++ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index e9cebbe34..9bee9d62d 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -52,7 +52,7 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : zoomed_(false) { connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::ToolChanged); - + // Initilises hand_tool_ based on currently selected tool. ToolChanged(Core::instance()->tool()); } @@ -76,9 +76,9 @@ void ViewerDisplayWidget::SetMatrixZoom(const QMatrix4x4 &mat) void ViewerDisplayWidget::IsZoomed(bool flag) { zoomed_ = flag; - // If the image is smaller than the container widget we disable translation + // If the image is smaller than the container widget we reset the translation. if (!flag) { - QMatrix4x4 mat; + QMatrix4x4 mat; // defaults to identity matrix. SetMatrixTranslate(mat); } } @@ -97,6 +97,7 @@ void ViewerDisplayWidget::ToolChanged(Tool::Item tool) QMatrix4x4 ViewerDisplayWidget::GetCompleteMatrix() { QMatrix4x4 mat; + // Images is scaled, the translated. return translate_matrix_ * scale_matrix_ * mat; } @@ -183,13 +184,13 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) return; } - // reset translation + // Reset translation. if (event->button() == Qt::MiddleButton && event->modifiers() & Qt::ControlModifier) { - QMatrix4x4 mat; + QMatrix4x4 mat; // Identity matrix SetMatrixTranslate(mat); } - // If translation is enabled get current position in preperation for move event + // If translation is enabled get current position in preperation for move event. if ((event->button() == Qt::MiddleButton || hand_tool_) && zoomed_) { position_ = event->pos(); return; diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index a43e58804..fed5febb4 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -117,8 +117,17 @@ public slots: */ void SetImage(FramePtr in_buffer); + /** + * @brief Set zoomed_ flag if the viewersizer has zoomed the image to be larger than the widget. + * + * If the image is smaller than the widget the translation is reset so the image is centered. + */ void IsZoomed(bool flag); + /** + * @brief Changes the pointer type if the tool is changed to the hand tool. Otherwise resets the pointer to it's + * normal type. + */ void ToolChanged(Tool::Item tool); signals: @@ -208,10 +217,13 @@ private: bool zoomed_; /** - * @brief position of mouse to calculate delta from. + * @brief Position of mouse to calculate delta from. */ QPoint position_; + /** + * @brief Set if the hand tool is selected. + */ bool hand_tool_; private slots: diff --git a/app/widget/viewer/viewersizer.h b/app/widget/viewer/viewersizer.h index 3948e2e8f..84ec727b3 100644 --- a/app/widget/viewer/viewersizer.h +++ b/app/widget/viewer/viewersizer.h @@ -65,6 +65,10 @@ public: signals: void RequestMatrix(const QMatrix4x4& matrix); + + /** + * @brief Tells the viewerdisplay widget if the image is enlarged to be bigger than the widget or not. + */ void IsZoomed(bool flag); protected: From c7356622320c86601a1d32e9918c02f78a2b4215 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Fri, 19 Jun 2020 14:16:21 +0100 Subject: [PATCH 09/16] First play with safe areas --- app/widget/viewer/viewerdisplay.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 9bee9d62d..a078b2f58 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -328,6 +328,13 @@ void ViewerDisplayWidget::paintGL() // Draw action/title safe areas if (safe_margin_.is_enabled()) { QPainter p(this); + float* data = GetCompleteMatrix().data(); + QMatrix mat; + mat.translate(data[12], data[13]); + mat.scale(data[0], data[5]); + //p.setTransform(GetCompleteMatrix().toTransform()); + + printf("Data[12]: %f\n", *(data+12)); p.setPen(Qt::lightGray); p.setBrush(Qt::NoBrush); @@ -345,8 +352,14 @@ void ViewerDisplayWidget::paintGL() y = height() / 2 - h / 2; } } - - p.drawRect(w / 20 + x, h / 20 + y, w / 10 * 9, h / 10 * 9); + QRect rect1(w / 20 + x, h / 20 + y, w / 10 * 9, h / 10 * 9); + //p.drawRect(w / 20 + x, h / 20 + y, w / 10 * 9, h / 10 * 9); + // scale translation by width(), height() and halve + // scale should already be correct, but needs offsetting + rect1.translate(*(data + 12)*width()*0.5, *(data + 13)*height()*-0.5); + rect1.setWidth(rect1.width() * *(data)); + rect1.setHeight(rect1.height() * *(data + 5)); + p.drawRect(rect1); p.drawRect(w / 10 + x, h / 10 + y, w / 10 * 8, h / 10 * 8); int cross = qMin(w, h) / 32; From 61618a9a1452903a54a5577b247e8671baddf834 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Fri, 19 Jun 2020 16:41:29 +0100 Subject: [PATCH 10/16] Use a world transform for QPainter World transform is based of the view matrix and can be used on any QPainter that needs to draw on the canvas and move with the mouse/ zoom. --- app/widget/viewer/viewerdisplay.cpp | 40 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index a078b2f58..1ceb97c8f 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -313,6 +313,25 @@ void ViewerDisplayWidget::paintGL() } + /* + * Get matrix elements (roughly) as below in column major order + * + * | Sx 0 0 Tx | + * | 0 Sy 0 Ty | + * | 0 0 Sz Tz | + * | 0 0 0 1 | + */ + float *data = GetCompleteMatrix().data(); + QTransform world; + // Move corner of canvas to correct point + world.translate(width() * 0.5 - width() * *(data)*0.5, + height() * 0.5 - height() * *(data + 5) * 0.5); + // Scale + world.scale(*(data), *(data + 5)); + // Translate for mouse movement + world.translate(*(data + 12) * width() * 0.5 / *(data), + *(data + 13) * height() * -0.5 / *(data + 5)); + // Draw gizmos if we have any if (gizmos_) { GizmoTraverser gt(QSize(gizmo_params_.width(), gizmo_params_.height())); @@ -322,19 +341,16 @@ void ViewerDisplayWidget::paintGL() gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time)); QPainter p(this); + p.setWorldTransform(world); gizmos_->DrawGizmos(gizmo_db_, &p, QVector2D(GetTexturePosition(size())), size()); } // Draw action/title safe areas if (safe_margin_.is_enabled()) { QPainter p(this); - float* data = GetCompleteMatrix().data(); - QMatrix mat; - mat.translate(data[12], data[13]); - mat.scale(data[0], data[5]); - //p.setTransform(GetCompleteMatrix().toTransform()); - - printf("Data[12]: %f\n", *(data+12)); + p.setWorldTransform(world); + + p.setPen(Qt::lightGray); p.setBrush(Qt::NoBrush); @@ -352,14 +368,8 @@ void ViewerDisplayWidget::paintGL() y = height() / 2 - h / 2; } } - QRect rect1(w / 20 + x, h / 20 + y, w / 10 * 9, h / 10 * 9); - //p.drawRect(w / 20 + x, h / 20 + y, w / 10 * 9, h / 10 * 9); - // scale translation by width(), height() and halve - // scale should already be correct, but needs offsetting - rect1.translate(*(data + 12)*width()*0.5, *(data + 13)*height()*-0.5); - rect1.setWidth(rect1.width() * *(data)); - rect1.setHeight(rect1.height() * *(data + 5)); - p.drawRect(rect1); + + p.drawRect(w / 20 + x, h / 20 + y, w / 10 * 9, h / 10 * 9); p.drawRect(w / 10 + x, h / 10 + y, w / 10 * 8, h / 10 * 8); int cross = qMin(w, h) / 32; From 1c6aebdcbe08dedd424ea776d990de009e8bd5b0 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sun, 21 Jun 2020 18:33:41 +0100 Subject: [PATCH 11/16] Move the world transform code to its own function It seems like something that could come in handy elsewhere when drawing stuff to the viewer. --- app/widget/viewer/viewerdisplay.cpp | 41 ++++++++++++++++------------- app/widget/viewer/viewerdisplay.h | 6 +++++ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 1ceb97c8f..c0d3dd858 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -175,6 +175,28 @@ FramePtr ViewerDisplayWidget::last_loaded_buffer() const return last_loaded_buffer_; } +QTransform ViewerDisplayWidget::GenerateWorldTransform() +{ + /* + * Get matrix elements (roughly) as below in column major order + * + * | Sx 0 0 Tx | + * | 0 Sy 0 Ty | + * | 0 0 Sz Tz | + * | 0 0 0 1 | + */ + float *data = GetCompleteMatrix().data(); + QTransform world; + // Move corner of canvas to correct point + world.translate(width() * 0.5 - width() * *(data)*0.5, height() * 0.5 - height() * *(data + 5) * 0.5); + // Scale + world.scale(*(data), *(data + 5)); + // Translate for mouse movement + world.translate(*(data + 12) * width() * 0.5 / *(data), *(data + 13) * height() * -0.5 / *(data + 5)); + + return world; +} + void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { if (gizmos_ @@ -313,24 +335,7 @@ void ViewerDisplayWidget::paintGL() } - /* - * Get matrix elements (roughly) as below in column major order - * - * | Sx 0 0 Tx | - * | 0 Sy 0 Ty | - * | 0 0 Sz Tz | - * | 0 0 0 1 | - */ - float *data = GetCompleteMatrix().data(); - QTransform world; - // Move corner of canvas to correct point - world.translate(width() * 0.5 - width() * *(data)*0.5, - height() * 0.5 - height() * *(data + 5) * 0.5); - // Scale - world.scale(*(data), *(data + 5)); - // Translate for mouse movement - world.translate(*(data + 12) * width() * 0.5 / *(data), - *(data + 13) * height() * -0.5 / *(data + 5)); + QTransform world = GenerateWorldTransform(); // Draw gizmos if we have any if (gizmos_) { diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index fed5febb4..7d6a5502e 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -87,6 +87,12 @@ public: FramePtr last_loaded_buffer() const; + /** + * @brief Return a QTransform that contains all the scale and translation data (inc. mouse drags) + * that can be used to set the world transform for a QPainter. + */ + QTransform GenerateWorldTransform(); + public slots: /** * @brief Set the transformation matrix to draw with From ccb6efd6b640ba2067ed9ffa8d64fc6ba0409633 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sun, 21 Jun 2020 19:31:40 +0100 Subject: [PATCH 12/16] Make gizmos work with translated/zoomed image Added a new function that inverts the world transform and applies it to a point. This allows the gizmo code to work in it's own space and not need to know is the image has been zoomed or translated. --- app/widget/viewer/viewerdisplay.cpp | 16 ++++++++++++++-- app/widget/viewer/viewerdisplay.h | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index c0d3dd858..d89813c1a 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -197,10 +197,20 @@ QTransform ViewerDisplayWidget::GenerateWorldTransform() return world; } +QPoint ViewerDisplayWidget::TransformViewerSpaceToGizmoSpace(QPoint pos) +{ + /* + * Inversion will only fail is the viewer has been scaled by 0 in any direction + * which I think should never happen. Also I don't know what we'd do if it does. + */ + return pos * GenerateWorldTransform().inverted(); +} + void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { if (gizmos_ - && gizmos_->GizmoPress(gizmo_db_, event->pos(), QVector2D(GetTexturePosition(size())), size())) { + && gizmos_->GizmoPress(gizmo_db_, TransformViewerSpaceToGizmoSpace(event->pos()), + QVector2D(GetTexturePosition(size())), size())) { gizmo_click_ = true; gizmo_drag_time_ = GetGizmoTime(); return; @@ -246,7 +256,9 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) } if (gizmo_click_) { - gizmos_->GizmoMove(event->pos(), QVector2D(GetTexturePosition(size())), gizmo_drag_time_); + gizmos_->GizmoMove(TransformViewerSpaceToGizmoSpace(event->pos()), + QVector2D(GetTexturePosition(size())), gizmo_drag_time_); + update(); return; } diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 7d6a5502e..f81cf71d8 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -93,6 +93,8 @@ public: */ QTransform GenerateWorldTransform(); + QPoint TransformViewerSpaceToGizmoSpace(QPoint pos); + public slots: /** * @brief Set the transformation matrix to draw with From 8f326c5193bd472b344818bcb8a21790c2598df6 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Sun, 21 Jun 2020 19:59:44 +0100 Subject: [PATCH 13/16] Fix pixel sampler with translate/zoomed image Pixel sampler now works with a zoomed/translated image. As usual we have to flip the y translation as OpenGl stores images upside down. Need to look at a better way of handling this. --- app/widget/viewer/viewerdisplay.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index d89813c1a..867b922cd 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -271,8 +271,10 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) 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); + QMatrix4x4 transform = GetCompleteMatrix(); + *(transform.data() + 13) = *(transform.data() + 13) * -1.0f; - pixel_pos = pixel_pos * GetCompleteMatrix().inverted(); + pixel_pos = transform.inverted() * pixel_pos; int frame_x = qRound((pixel_pos.x() + 1.0f) * 0.5f * last_loaded_buffer_->width()); int frame_y = qRound((pixel_pos.y() + 1.0f) * 0.5f * last_loaded_buffer_->height()); From fdce84f34c0b5222a7d8191580d224a57e62dc80 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 22 Jun 2020 13:01:10 +0100 Subject: [PATCH 14/16] Cleanup flipped Y axis code There are now two functions to get the full matrix for the transformed image. One that returns as is and one that returns with the Y translation flipped for OpenGL. Also some minor bug fixing. --- app/widget/viewer/viewerdisplay.cpp | 34 +++++++++++++++++++---------- app/widget/viewer/viewerdisplay.h | 11 ++++++++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 867b922cd..2ecb54222 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -49,7 +49,8 @@ ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) : gizmos_(nullptr), gizmo_click_(false), last_loaded_buffer_(nullptr), - zoomed_(false) + zoomed_(false), + hand_tool_clicked_(false) { connect(Core::instance(), &Core::ToolChanged, this, &ViewerDisplayWidget::ToolChanged); // Initilises hand_tool_ based on currently selected tool. @@ -97,10 +98,19 @@ void ViewerDisplayWidget::ToolChanged(Tool::Item tool) QMatrix4x4 ViewerDisplayWidget::GetCompleteMatrix() { QMatrix4x4 mat; - // Images is scaled, the translated. + // Images is scaled, then translated. return translate_matrix_ * scale_matrix_ * mat; } +QMatrix4x4 ViewerDisplayWidget::GetCompleteMatrixFlippedYTranslation() { + QMatrix4x4 mat; + // Images is scaled, then translated. + mat = translate_matrix_ * scale_matrix_ * mat; + // Y translation is flipped for OpenGL usage + *(mat.data() + 13) = *(mat.data() + 13) * -1.0f; + return mat; +} + void ViewerDisplayWidget::SetSignalCursorColorEnabled(bool e) { signal_cursor_color_ = e; @@ -192,7 +202,7 @@ QTransform ViewerDisplayWidget::GenerateWorldTransform() // Scale world.scale(*(data), *(data + 5)); // Translate for mouse movement - world.translate(*(data + 12) * width() * 0.5 / *(data), *(data + 13) * height() * -0.5 / *(data + 5)); + world.translate(*(data + 12) * width() * 0.5 / *(data), *(data + 13) * height() * 0.5 / *(data + 5)); return world; } @@ -208,7 +218,7 @@ QPoint ViewerDisplayWidget::TransformViewerSpaceToGizmoSpace(QPoint pos) void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { - if (gizmos_ + if (event->button() == Qt::LeftButton && gizmos_ && gizmos_->GizmoPress(gizmo_db_, TransformViewerSpaceToGizmoSpace(event->pos()), QVector2D(GetTexturePosition(size())), size())) { gizmo_click_ = true; @@ -220,11 +230,13 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) if (event->button() == Qt::MiddleButton && event->modifiers() & Qt::ControlModifier) { QMatrix4x4 mat; // Identity matrix SetMatrixTranslate(mat); + return; } // If translation is enabled get current position in preperation for move event. if ((event->button() == Qt::MiddleButton || hand_tool_) && zoomed_) { position_ = event->pos(); + if (hand_tool_) hand_tool_clicked_ = true; return; } @@ -238,7 +250,7 @@ void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) { // Only allow translation if the image is larger than the container widget - if ((event->buttons() & Qt::MiddleButton || hand_tool_) && zoomed_) { + if ((event->buttons() & Qt::MiddleButton || hand_tool_clicked_) && zoomed_) { QPointF delta = event->pos() - position_; // scale delta to widget size delta.setX(2 * delta.x() / width()); @@ -246,8 +258,8 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) QMatrix4x4 mat; mat = GetMatrixTranslate(); - // Have to invert y axis, possibly because of something in the OpenGL code? - mat.translate(delta.x(), -1.0f * delta.y()); + + mat.translate(delta.x(), delta.y()); SetMatrixTranslate(mat); // get new start position @@ -271,10 +283,8 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) 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); - QMatrix4x4 transform = GetCompleteMatrix(); - *(transform.data() + 13) = *(transform.data() + 13) * -1.0f; - pixel_pos = transform.inverted() * pixel_pos; + pixel_pos = GetCompleteMatrix().inverted() * pixel_pos; int frame_x = qRound((pixel_pos.x() + 1.0f) * 0.5f * last_loaded_buffer_->width()); int frame_y = qRound((pixel_pos.y() + 1.0f) * 0.5f * last_loaded_buffer_->height()); @@ -296,6 +306,8 @@ void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event) return; } + hand_tool_clicked_ = false; + QOpenGLWidget::mouseReleaseEvent(event); } @@ -342,7 +354,7 @@ void ViewerDisplayWidget::paintGL() f->glBindTexture(GL_TEXTURE_2D, texture_.texture()); // Blit using the color service - color_service()->ProcessOpenGL(true, GetCompleteMatrix()); + color_service()->ProcessOpenGL(true, GetCompleteMatrixFlippedYTranslation()); // Release retrieved texture f->glBindTexture(GL_TEXTURE_2D, 0); diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index f81cf71d8..09dad2ac7 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -78,6 +78,12 @@ public: */ QMatrix4x4 GetCompleteMatrix(); + /** + * @brief Return the complete translation and scale matrix but with the Y translation flipped + * as OpenGL stores textures "upside down". + */ + QMatrix4x4 GetCompleteMatrixFlippedYTranslation(); + const ViewerSafeMarginInfo& GetSafeMargin() const; void SetSafeMargins(const ViewerSafeMarginInfo& safe_margin); @@ -234,6 +240,11 @@ private: */ bool hand_tool_; + /** + * @brief Set if the hand tool is selected and viewer is clicked. + */ + bool hand_tool_clicked_; + private slots: /** * @brief Slot to connect just before the OpenGL context is destroyed to clean up resources From 53b8e7fa0316be42db01f2293b69b0b74d35f31e Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 22 Jun 2020 13:27:54 +0100 Subject: [PATCH 15/16] Fix comments and grammer --- app/widget/viewer/viewerdisplay.cpp | 6 +++--- app/widget/viewer/viewerdisplay.h | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index 2ecb54222..c5e5492bb 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -207,7 +207,7 @@ QTransform ViewerDisplayWidget::GenerateWorldTransform() return world; } -QPoint ViewerDisplayWidget::TransformViewerSpaceToGizmoSpace(QPoint pos) +QPoint ViewerDisplayWidget::TransformViewerSpaceToBufferSpace(QPoint pos) { /* * Inversion will only fail is the viewer has been scaled by 0 in any direction @@ -219,7 +219,7 @@ QPoint ViewerDisplayWidget::TransformViewerSpaceToGizmoSpace(QPoint pos) void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton && gizmos_ - && gizmos_->GizmoPress(gizmo_db_, TransformViewerSpaceToGizmoSpace(event->pos()), + && gizmos_->GizmoPress(gizmo_db_, TransformViewerSpaceToBufferSpace(event->pos()), QVector2D(GetTexturePosition(size())), size())) { gizmo_click_ = true; gizmo_drag_time_ = GetGizmoTime(); @@ -268,7 +268,7 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) } if (gizmo_click_) { - gizmos_->GizmoMove(TransformViewerSpaceToGizmoSpace(event->pos()), + gizmos_->GizmoMove(TransformViewerSpaceToBufferSpace(event->pos()), QVector2D(GetTexturePosition(size())), gizmo_drag_time_); update(); return; diff --git a/app/widget/viewer/viewerdisplay.h b/app/widget/viewer/viewerdisplay.h index 09dad2ac7..29bf30706 100644 --- a/app/widget/viewer/viewerdisplay.h +++ b/app/widget/viewer/viewerdisplay.h @@ -99,7 +99,11 @@ public: */ QTransform GenerateWorldTransform(); - QPoint TransformViewerSpaceToGizmoSpace(QPoint pos); + /** + * @brief Transform a point from viewer space to the buffer space. + * Multiplies by the inverted transform matrix to undo the scaling and translation. + */ + QPoint TransformViewerSpaceToBufferSpace(QPoint pos); public slots: /** From 63c306c77082eaa1522d9cb058da17763a414871 Mon Sep 17 00:00:00 2001 From: Thomas Wilshaw Date: Mon, 22 Jun 2020 13:45:51 +0100 Subject: [PATCH 16/16] Fix typos --- app/widget/viewer/viewerdisplay.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index c5e5492bb..56cfcfa40 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -104,7 +104,7 @@ QMatrix4x4 ViewerDisplayWidget::GetCompleteMatrix() QMatrix4x4 ViewerDisplayWidget::GetCompleteMatrixFlippedYTranslation() { QMatrix4x4 mat; - // Images is scaled, then translated. + // Image is scaled, then translated. mat = translate_matrix_ * scale_matrix_ * mat; // Y translation is flipped for OpenGL usage *(mat.data() + 13) = *(mat.data() + 13) * -1.0f; @@ -210,8 +210,8 @@ QTransform ViewerDisplayWidget::GenerateWorldTransform() QPoint ViewerDisplayWidget::TransformViewerSpaceToBufferSpace(QPoint pos) { /* - * Inversion will only fail is the viewer has been scaled by 0 in any direction - * which I think should never happen. Also I don't know what we'd do if it does. + * Inversion will only fail if the viewer has been scaled by 0 in any direction + * which I think should never happen. */ return pos * GenerateWorldTransform().inverted(); } @@ -252,7 +252,7 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) // Only allow translation if the image is larger than the container widget if ((event->buttons() & Qt::MiddleButton || hand_tool_clicked_) && zoomed_) { QPointF delta = event->pos() - position_; - // scale delta to widget size + // Scale delta to widget size delta.setX(2 * delta.x() / width()); delta.setY(2 * delta.y() / height()); @@ -262,7 +262,7 @@ void ViewerDisplayWidget::mouseMoveEvent(QMouseEvent *event) mat.translate(delta.x(), delta.y()); SetMatrixTranslate(mat); - // get new start position + // Get new start position position_ = event-> pos(); return; } @@ -381,7 +381,6 @@ void ViewerDisplayWidget::paintGL() QPainter p(this); p.setWorldTransform(world); - p.setPen(Qt::lightGray); p.setBrush(Qt::NoBrush);