Files
fmviewer3/project/fm_viewer/fav/widget/QOpenGLWidget.cpp
2026-02-21 17:11:31 +09:00

224 lines
5.7 KiB
C++

/******************************************************************************
QtAV: Multimedia framework based on Qt and FFmpeg
Copyright (C) 2015 Wang Bin <wbsecg1@gmail.com>
* This file is part of QtAV
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
******************************************************************************/
#include "QOpenGLWidget.h"
#if !(REMOVE_OPENGL_WIDGET)
#include <QResizeEvent>
#include <QWindow>
#include <QDebug>
// for dynamicgl. qglfunctions before qt5.3 does not have portable gl functions
#ifdef QT_OPENGL_DYNAMIC
#define DYGL(glFunc) QOpenGLContext::currentContext()->functions()->glFunc
#else
#define DYGL(glFunc) glFunc
#endif
namespace FAV {
// TODO: is QOpenGLWidgetPaintDevice required?
class QOpenGLWidgetPaintDevice : public QOpenGLPaintDevice
{
public:
QOpenGLWidgetPaintDevice(QOpenGLWidget *widget)
: QOpenGLPaintDevice()
, w(widget)
{ }
void ensureActiveTarget() Q_DECL_OVERRIDE {
if (QOpenGLContext::currentContext() != w->context()) {
w->makeCurrent();
}
}
private:
QOpenGLWidget *w;
};
QOpenGLWidget::QOpenGLWidget(QWidget *parent, Qt::WindowFlags f)
: QWidget(parent, f)
, m_initialized(false)
, m_fakeHidden(false)
, m_context(0)
, m_paintDevice(0)
{
setAttribute(Qt::WA_NativeWindow); // ensure windowHandle() is not null
// WA_PaintOnScreen: QWidget::paintEngine: Should no longer be called. This flag is only supported on X11 and it disables double buffering
//setAttribute(Qt::WA_PaintOnScreen); // enforce native window, so windowHandle() is not null
setAttribute(Qt::WA_NoSystemBackground);
//setAutoFillBackground(true); // for compatibility
// FIXME: why setSurfaceType crash?
//windowHandle()->setSurfaceType(QWindow::OpenGLSurface);
}
QOpenGLWidget::~QOpenGLWidget()
{
delete m_paintDevice;
}
void QOpenGLWidget::setFormat(const QSurfaceFormat &format)
{
m_requestedFormat = format;
}
QSurfaceFormat QOpenGLWidget::format() const
{
return m_requestedFormat;
}
bool QOpenGLWidget::isValid() const
{
return m_initialized && m_context->isValid();
}
void QOpenGLWidget::makeCurrent()
{
if (!m_initialized) {
qWarning("QOpenGLWidget: Cannot make uninitialized widget current");
return;
}
if (!windowHandle()) {
qWarning("QOpenGLWidget: No window handle");
return;
}
m_context->makeCurrent((QSurface*)windowHandle());
}
void QOpenGLWidget::doneCurrent()
{
if (!m_initialized)
return;
m_context->doneCurrent();
}
QOpenGLContext *QOpenGLWidget::context() const
{
return m_context;
}
QPaintDevice* QOpenGLWidget::redirected(QPoint *offset) const
{
Q_UNUSED(offset);
// TODO: check backing store like Qt does
return m_paintDevice;
}
void QOpenGLWidget::initializeGL()
{
}
void QOpenGLWidget::paintGL()
{
}
void QOpenGLWidget::resizeGL(int w, int h)
{
Q_UNUSED(w);
Q_UNUSED(h);
}
void QOpenGLWidget::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e);
if (!m_initialized)
return;
if (updatesEnabled())
render();
}
void QOpenGLWidget::resizeEvent(QResizeEvent *e)
{
if (e->size().isEmpty()) {
m_fakeHidden = true;
return;
}
m_fakeHidden = false;
initialize();
if (!m_initialized)
return;
//recreateFbo();
resizeGL(width(), height());
invokeUserPaint();
//resolveSamples();
}
void QOpenGLWidget::initialize()
{
if (m_initialized)
return;
QWindow *win = windowHandle();
if (!win) {
qWarning("QOpenGLWidget: No window handle");
return;
}
m_context = new QOpenGLContext(this);
// TODO: shareContext()
m_context->setFormat(m_requestedFormat);
if (!m_context->create()) {
qWarning("QOpenGLWidget: Failed to create context");
return;
}
//m_context = QOpenGLContext::currentContext();
if (!m_context) {
qWarning("QOpenGLWidget: QOpenGLContext is null");
return;
}
if (!m_context->makeCurrent(win)) {
qWarning("QOpenGLWidget: Failed to make context current");
return;
}
m_paintDevice = new QOpenGLWidgetPaintDevice(this);
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
m_paintDevice->setSize(size() * devicePixelRatio());
m_paintDevice->setDevicePixelRatio(devicePixelRatio());
#else
m_paintDevice->setSize(size());
#endif
m_initialized = true;
initializeGL();
}
void QOpenGLWidget::render()
{
if (m_fakeHidden || !m_initialized)
return;
// QOpenGLContext::swapBuffers() called with non-exposed window, behavior is undefined
QWindow *win = windowHandle();
if (!win || !win->isExposed())
return;
makeCurrent();
invokeUserPaint();
m_context->swapBuffers(win);
}
void QOpenGLWidget::invokeUserPaint()
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 1 , 0)
DYGL(glViewport(0, 0, width()*devicePixelRatio(), height()*devicePixelRatio()));
#else
DYGL(glViewport(0, 0, width(), height()));
#endif
paintGL();
DYGL(glFlush());
}
} //namespace FAV
#endif // @REMOVE_OPENGL_WIDGET