Files
oak-editor/app/widget/viewer/viewerdisplay.cpp
T
Thomas Wilshaw 2174100342 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.
2020-06-16 11:53:34 +01:00

374 lines
9.5 KiB
C++

/***
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 "viewerdisplay.h"
#include <OpenImageIO/imagebuf.h>
#include <QFileInfo>
#include <QMessageBox>
#include <QMouseEvent>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include <QPainter>
#include "common/define.h"
#include "common/functiontimer.h"
#include "gizmotraverser.h"
#include "render/backend/opengl/openglrenderfunctions.h"
#include "render/backend/opengl/openglshader.h"
#include "render/pixelformat.h"
OLIVE_NAMESPACE_ENTER
#ifdef Q_OS_LINUX
bool ViewerDisplayWidget::nouveau_check_done_ = false;
#endif
ViewerDisplayWidget::ViewerDisplayWidget(QWidget *parent) :
ManagedDisplayWidget(parent),
signal_cursor_color_(false),
gizmos_(nullptr),
gizmo_click_(false),
last_loaded_buffer_(nullptr)
{
}
ViewerDisplayWidget::~ViewerDisplayWidget()
{
ContextCleanup();
}
void ViewerDisplayWidget::SetMatrixTranslate(const QMatrix4x4 &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;
setMouseTracking(e);
}
void ViewerDisplayWidget::SetImage(FramePtr in_buffer)
{
last_loaded_buffer_ = in_buffer;
if (last_loaded_buffer_) {
makeCurrent();
if (!texture_.IsCreated()
|| texture_.width() != in_buffer->width()
|| texture_.height() != in_buffer->height()
|| texture_.format() != in_buffer->format()) {
texture_.Create(context(), in_buffer->video_params(), in_buffer->data(), in_buffer->linesize_pixels());
} else {
texture_.Upload(in_buffer);
}
doneCurrent();
}
update();
}
const ViewerSafeMarginInfo &ViewerDisplayWidget::GetSafeMargin() const
{
return safe_margin_;
}
void ViewerDisplayWidget::SetSafeMargins(const ViewerSafeMarginInfo &safe_margin)
{
if (safe_margin_ != safe_margin) {
safe_margin_ = safe_margin;
update();
}
}
void ViewerDisplayWidget::SetGizmos(Node *node)
{
if (gizmos_ != node) {
gizmos_ = node;
update();
}
}
void ViewerDisplayWidget::SetVideoParams(const VideoParams &params)
{
gizmo_params_ = params;
if (gizmos_) {
update();
}
}
void ViewerDisplayWidget::SetTime(const rational &time)
{
time_ = time;
if (gizmos_) {
update();
}
}
FramePtr ViewerDisplayWidget::last_loaded_buffer() const
{
return last_loaded_buffer_;
}
void ViewerDisplayWidget::mousePressEvent(QMouseEvent *event)
{
if (gizmos_
&& gizmos_->GizmoPress(gizmo_db_, event->pos(), QVector2D(GetTexturePosition(size())), size())) {
gizmo_click_ = true;
gizmo_drag_time_ = GetGizmoTime();
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) {
emit DragStarted();
}
}
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<float>(new_pos.x()) / width(), static_cast<float>(-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;
}
QOpenGLWidget::mouseMoveEvent(event);
if (signal_cursor_color_) {
Color reference, display;
if (last_loaded_buffer_) {
QVector3D pixel_pos(static_cast<float>(event->x()) / static_cast<float>(width()) * 2.0f - 1.0f,
static_cast<float>(event->y()) / static_cast<float>(height()) * 2.0f - 1.0f,
0);
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());
reference = last_loaded_buffer_->get_pixel(frame_x, frame_y);
display = color_service()->ConvertColor(reference);
}
emit CursorColor(reference, display);
}
}
void ViewerDisplayWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (gizmo_click_) {
gizmos_->GizmoRelease();
gizmo_click_ = false;
return;
}
QOpenGLWidget::mouseReleaseEvent(event);
}
QMatrix4x4 ViewerDisplayWidget::GetMatrixTranslate()
{
return translate_matrix_;
}
void ViewerDisplayWidget::initializeGL()
{
ManagedDisplayWidget::initializeGL();
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ViewerDisplayWidget::ContextCleanup, Qt::DirectConnection);
#ifdef Q_OS_LINUX
if (!nouveau_check_done_) {
const char* vendor = reinterpret_cast<const char*>(context()->functions()->glGetString(GL_VENDOR));
if (!strcmp(vendor, "nouveau")) {
// Working with Qt widgets in this function segfaults, so we queue the messagebox for later
QMetaObject::invokeMethod(this,
"ShowNouveauWarning",
Qt::QueuedConnection);
}
nouveau_check_done_ = true;
}
#endif
}
void ViewerDisplayWidget::paintGL()
{
// Get functions attached to this context (they will already be initialized)
QOpenGLFunctions* f = context()->functions();
// Clear background to empty
f->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
f->glClear(GL_COLOR_BUFFER_BIT);
// We only draw if we have a pipeline
if (last_loaded_buffer_ && color_service()) {
// 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());
// Release retrieved texture
f->glBindTexture(GL_TEXTURE_2D, 0);
}
// Draw gizmos if we have any
if (gizmos_) {
GizmoTraverser gt(QSize(gizmo_params_.width(), gizmo_params_.height()));
rational node_time = GetGizmoTime();
gizmo_db_ = gt.GenerateDatabase(gizmos_, TimeRange(node_time, node_time));
QPainter p(this);
gizmos_->DrawGizmos(gizmo_db_, &p, QVector2D(GetTexturePosition(size())), size());
}
// Draw action/title safe areas
if (safe_margin_.is_enabled()) {
QPainter p(this);
p.setPen(Qt::lightGray);
p.setBrush(Qt::NoBrush);
int x = 0, y = 0, w = width(), h = height();
if (safe_margin_.custom_ratio()) {
double widget_ar = static_cast<double>(width()) / static_cast<double>(height());
if (widget_ar > safe_margin_.ratio()) {
// Widget is wider than margins
w = h * safe_margin_.ratio();
x = width() / 2 - w / 2;
} else {
h = w / safe_margin_.ratio();
y = height() / 2 - h / 2;
}
}
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;
QLine lines[] = {QLine(rect().center().x() - cross, rect().center().y(),rect().center().x() + cross, rect().center().y()),
QLine(rect().center().x(), rect().center().y() - cross, rect().center().x(), rect().center().y() + cross)};
p.drawLines(lines, 2);
}
}
QPointF ViewerDisplayWidget::GetTexturePosition(const QPoint &screen_pos)
{
return GetTexturePosition(screen_pos.x(), screen_pos.y());
}
QPointF ViewerDisplayWidget::GetTexturePosition(const QSize &size)
{
return GetTexturePosition(size.width(), size.height());
}
QPointF ViewerDisplayWidget::GetTexturePosition(const double &x, const double &y)
{
return QPointF(x / gizmo_params_.width(),
y / gizmo_params_.height());
}
rational ViewerDisplayWidget::GetGizmoTime()
{
return GetAdjustedTime(GetTimeTarget(), gizmos_, time_, NodeParam::kInput);
}
#ifdef Q_OS_LINUX
void ViewerDisplayWidget::ShowNouveauWarning()
{
QMessageBox::warning(this,
tr("Driver Warning"),
tr("Olive has detected your system is using the Nouveau graphics driver.\n\nThis driver is "
"known to have stability and performance issues with Olive. It is highly recommended "
"you install the proprietary NVIDIA driver before continuing to use Olive."),
QMessageBox::Ok);
}
#endif
void ViewerDisplayWidget::ContextCleanup()
{
makeCurrent();
texture_.Destroy();
doneCurrent();
}
OLIVE_NAMESPACE_EXIT