Enabling QQuickWidget and QOpenGLWidget
Enable child widgets (without a native window) that render to an FBO and are composed with the raster backingstore by the platform plugin. A preliminary version of QOpenGLWidget is included as private API. Change-Id: I8f984a4d7db285069ce3d6564707942c823d890d Reviewed-by: Jørgen Lind <jorgen.lind@digia.com>
This commit is contained in:
parent
5ae5bebb93
commit
eacd58d4e7
@ -516,6 +516,7 @@ public:
|
||||
AA_SynthesizeTouchForUnhandledMouseEvents = 11,
|
||||
AA_SynthesizeMouseForUnhandledTouchEvents = 12,
|
||||
AA_UseHighDpiPixmaps = 13,
|
||||
AA_ForceRasterWidgets = 14,
|
||||
|
||||
// Add new attributes before this line
|
||||
AA_AttributeCount
|
||||
|
@ -165,6 +165,9 @@
|
||||
sizes in layout geometry calculations should typically divide by
|
||||
QPixmap::devicePixelRatio() to get device-independent layout geometry.
|
||||
|
||||
\value AA_ForceRasterWidgets Make top-level widgets use pure raster surfaces,
|
||||
and do not support non-native GL-based child widgets.
|
||||
|
||||
The following values are obsolete:
|
||||
|
||||
\value AA_ImmediateWidgetCreation This attribute is no longer fully
|
||||
|
@ -761,8 +761,7 @@ bool QOpenGLContext::makeCurrent(QSurface *surface)
|
||||
|
||||
if (!surface->surfaceHandle())
|
||||
return false;
|
||||
|
||||
if (surface->surfaceType() != QSurface::OpenGLSurface) {
|
||||
if (!surface->supportsOpenGL()) {
|
||||
qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface" << surface;
|
||||
return false;
|
||||
}
|
||||
@ -837,7 +836,7 @@ void QOpenGLContext::swapBuffers(QSurface *surface)
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface->surfaceType() != QSurface::OpenGLSurface) {
|
||||
if (!surface->supportsOpenGL()) {
|
||||
qWarning() << "QOpenGLContext::swapBuffers() called with non-opengl surface";
|
||||
return;
|
||||
}
|
||||
|
@ -95,7 +95,8 @@ public:
|
||||
NonFullScreenWindows,
|
||||
NativeWidgets,
|
||||
WindowManagement,
|
||||
SyncState
|
||||
SyncState,
|
||||
RasterGLSurface
|
||||
};
|
||||
|
||||
virtual ~QPlatformIntegration() { }
|
||||
|
@ -74,6 +74,9 @@ QT_BEGIN_NAMESPACE
|
||||
a software rasterizer like Qt's raster paint engine.
|
||||
\value OpenGLSurface The surface is an OpenGL compatible surface and can be used
|
||||
in conjunction with QOpenGLContext.
|
||||
\value RasterGLSurface The surface can be rendered to using a software rasterizer,
|
||||
and also supports OpenGL. This surface type is intended for internal Qt use, and
|
||||
requires the use of private API.
|
||||
*/
|
||||
|
||||
|
||||
@ -83,6 +86,19 @@ QT_BEGIN_NAMESPACE
|
||||
Returns the format of the surface.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Returns true if the surface is OpenGL compatible and can be used in
|
||||
conjunction with QOpenGLContext; otherwise returns false.
|
||||
|
||||
\since 5.3
|
||||
*/
|
||||
|
||||
bool QSurface::supportsOpenGL() const
|
||||
{
|
||||
SurfaceType type = surfaceType();
|
||||
return type == OpenGLSurface || type == RasterGLSurface;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn QPlatformSurface *QSurface::surfaceHandle() const
|
||||
|
||||
|
@ -64,7 +64,8 @@ public:
|
||||
|
||||
enum SurfaceType {
|
||||
RasterSurface,
|
||||
OpenGLSurface
|
||||
OpenGLSurface,
|
||||
RasterGLSurface
|
||||
};
|
||||
|
||||
virtual ~QSurface();
|
||||
@ -75,6 +76,7 @@ public:
|
||||
virtual QPlatformSurface *surfaceHandle() const = 0;
|
||||
|
||||
virtual SurfaceType surfaceType() const = 0;
|
||||
bool supportsOpenGL() const;
|
||||
|
||||
virtual QSize size() const = 0;
|
||||
|
||||
|
@ -44,6 +44,16 @@
|
||||
#include <qpixmap.h>
|
||||
#include <private/qwindow_p.h>
|
||||
|
||||
#include <qopengl.h>
|
||||
#include <qopenglcontext.h>
|
||||
#include <QtGui/QMatrix4x4>
|
||||
#include <QtGui/QOpenGLShaderProgram>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <QtGui/QOpenGLFunctions>
|
||||
#ifndef QT_NO_OPENGL
|
||||
#include <QtGui/private/qopengltextureblitter_p.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QPlatformBackingStorePrivate
|
||||
@ -51,13 +61,103 @@ class QPlatformBackingStorePrivate
|
||||
public:
|
||||
QPlatformBackingStorePrivate(QWindow *w)
|
||||
: window(w)
|
||||
#ifndef QT_NO_OPENGL
|
||||
, blitter(0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
~QPlatformBackingStorePrivate()
|
||||
{
|
||||
#ifndef QT_NO_OPENGL
|
||||
if (blitter)
|
||||
blitter->destroy();
|
||||
delete blitter;
|
||||
#endif
|
||||
}
|
||||
QWindow *window;
|
||||
QSize size;
|
||||
#ifndef QT_NO_OPENGL
|
||||
mutable GLuint textureId;
|
||||
mutable QSize textureSize;
|
||||
QOpenGLTextureBlitter *blitter;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
|
||||
struct QBackingstoreTextureInfo
|
||||
{
|
||||
GLuint textureId;
|
||||
QRect rect;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_MOVABLE_TYPE);
|
||||
|
||||
class QPlatformTextureListPrivate : public QObjectPrivate
|
||||
{
|
||||
public:
|
||||
QPlatformTextureListPrivate()
|
||||
: locked(false)
|
||||
{
|
||||
}
|
||||
|
||||
QList<QBackingstoreTextureInfo> textures;
|
||||
bool locked;
|
||||
};
|
||||
|
||||
QPlatformTextureList::QPlatformTextureList(QObject *parent)
|
||||
: QObject(*new QPlatformTextureListPrivate, parent)
|
||||
{
|
||||
}
|
||||
|
||||
QPlatformTextureList::~QPlatformTextureList()
|
||||
{
|
||||
}
|
||||
|
||||
int QPlatformTextureList::count() const
|
||||
{
|
||||
Q_D(const QPlatformTextureList);
|
||||
return d->textures.count();
|
||||
}
|
||||
|
||||
GLuint QPlatformTextureList::textureId(int index) const
|
||||
{
|
||||
Q_D(const QPlatformTextureList);
|
||||
return d->textures.at(index).textureId;
|
||||
}
|
||||
|
||||
QRect QPlatformTextureList::geometry(int index) const
|
||||
{
|
||||
Q_D(const QPlatformTextureList);
|
||||
return d->textures.at(index).rect;
|
||||
}
|
||||
|
||||
void QPlatformTextureList::lock(bool on)
|
||||
{
|
||||
Q_D(QPlatformTextureList);
|
||||
if (on != d->locked) {
|
||||
d->locked = on;
|
||||
emit locked(on);
|
||||
}
|
||||
}
|
||||
|
||||
bool QPlatformTextureList::isLocked() const
|
||||
{
|
||||
Q_D(const QPlatformTextureList);
|
||||
return d->locked;
|
||||
}
|
||||
|
||||
void QPlatformTextureList::appendTexture(GLuint textureId, const QRect &geometry)
|
||||
{
|
||||
Q_D(QPlatformTextureList);
|
||||
QBackingstoreTextureInfo bi;
|
||||
bi.textureId = textureId;
|
||||
bi.rect = geometry;
|
||||
d->textures.append(bi);
|
||||
}
|
||||
#endif // QT_NO_OPENGL
|
||||
|
||||
/*!
|
||||
\class QPlatformBackingStore
|
||||
\since 5.0
|
||||
@ -79,6 +179,147 @@ public:
|
||||
Note that the \a offset parameter is currently unused.
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
/*!
|
||||
Flushes the given \a region from the specified \a window onto the
|
||||
screen, and composes it with the specified \a textures.
|
||||
|
||||
The default implementation retrieves the contents using toTexture()
|
||||
and composes using OpenGL. May be reimplemented in subclasses if there
|
||||
is a more efficient native way to do it.
|
||||
|
||||
Note that the \a offset parameter is currently unused.
|
||||
*/
|
||||
|
||||
void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion,
|
||||
const QPoint &offset,
|
||||
QPlatformTextureList *textures, QOpenGLContext *context)
|
||||
{
|
||||
Q_UNUSED(offset);
|
||||
|
||||
context->makeCurrent(window);
|
||||
glViewport(0, 0, window->width(), window->height());
|
||||
|
||||
if (!d_ptr->blitter) {
|
||||
d_ptr->blitter = new QOpenGLTextureBlitter;
|
||||
d_ptr->blitter->create();
|
||||
}
|
||||
|
||||
d_ptr->blitter->bind();
|
||||
|
||||
QRect windowRect(QPoint(), window->size());
|
||||
for (int i = 0; i < textures->count(); ++i) {
|
||||
GLuint textureId = textures->textureId(i);
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
|
||||
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), windowRect,
|
||||
QOpenGLTextureBlitter::OriginTopLeft);
|
||||
d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginBottomLeft);
|
||||
}
|
||||
|
||||
GLuint textureId = toTexture(region);
|
||||
if (!textureId)
|
||||
return;
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(windowRect, windowRect,
|
||||
QOpenGLTextureBlitter::OriginTopLeft);
|
||||
d_ptr->blitter->setSwizzleRB(true);
|
||||
d_ptr->blitter->blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
|
||||
d_ptr->blitter->setSwizzleRB(false);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
d_ptr->blitter->release();
|
||||
context->swapBuffers(window);
|
||||
}
|
||||
|
||||
/*!
|
||||
Implemented in subclasses to return the content of the backingstore as a QImage.
|
||||
|
||||
If QPlatformIntegration::RasterGLSurface is supported, either this function or
|
||||
toTexture() must be implemented.
|
||||
|
||||
\sa toTexture()
|
||||
*/
|
||||
QImage QPlatformBackingStore::toImage() const
|
||||
{
|
||||
return QImage();
|
||||
}
|
||||
|
||||
/*!
|
||||
May be reimplemented in subclasses to return the content of the
|
||||
backingstore as an OpenGL texture. \a dirtyRegion is the part of the
|
||||
backingstore which may have changed since the last call to this function. The
|
||||
caller of this function must ensure that there is a current context.
|
||||
|
||||
The ownership of the texture is not transferred. The caller must not store
|
||||
the return value between calls, but instead call this function before each use.
|
||||
|
||||
The default implementation returns a cached texture if \a dirtyRegion is
|
||||
empty and the window has not been resized, otherwise it retrieves the
|
||||
content using toImage() and performs a texture upload.
|
||||
*/
|
||||
|
||||
GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion) const
|
||||
{
|
||||
QImage image = toImage();
|
||||
QSize imageSize = image.size();
|
||||
if (imageSize.isEmpty())
|
||||
return 0;
|
||||
|
||||
bool resized = d_ptr->textureSize != imageSize;
|
||||
if (dirtyRegion.isEmpty() && !resized)
|
||||
return d_ptr->textureId;
|
||||
|
||||
if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_RGBA8888)
|
||||
image = image.convertToFormat(QImage::Format_RGBA8888);
|
||||
|
||||
if (resized) {
|
||||
if (d_ptr->textureId)
|
||||
glDeleteTextures(1, &d_ptr->textureId);
|
||||
glGenTextures(1, &d_ptr->textureId);
|
||||
glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
|
||||
#ifndef QT_OPENGL_ES_2
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||
#endif
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageSize.width(), imageSize.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
const_cast<uchar*>(image.constBits()));
|
||||
d_ptr->textureSize = imageSize;
|
||||
} else {
|
||||
glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
|
||||
QRect imageRect = image.rect();
|
||||
QRect rect = dirtyRegion.boundingRect() & imageRect;
|
||||
// if the rect is wide enough it's cheaper to just
|
||||
// extend it instead of doing an image copy
|
||||
if (rect.width() >= imageRect.width() / 2) {
|
||||
rect.setX(0);
|
||||
rect.setWidth(imageRect.width());
|
||||
}
|
||||
|
||||
// if the sub-rect is full-width we can pass the image data directly to
|
||||
// OpenGL instead of copying, since there's no gap between scanlines
|
||||
|
||||
if (rect.width() == imageRect.width()) {
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
image.constScanLine(rect.y()));
|
||||
} else {
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
image.copy(rect).constBits());
|
||||
}
|
||||
}
|
||||
|
||||
return d_ptr->textureId;
|
||||
}
|
||||
#endif // QT_NO_OPENGL
|
||||
|
||||
/*!
|
||||
\fn QPaintDevice* QPlatformBackingStore::paintDevice()
|
||||
|
||||
|
@ -52,9 +52,11 @@
|
||||
//
|
||||
|
||||
#include <QtCore/qrect.h>
|
||||
#include <QtCore/qobject.h>
|
||||
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtGui/qregion.h>
|
||||
#include <QtGui/qopengl.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -65,6 +67,31 @@ class QPoint;
|
||||
class QImage;
|
||||
class QPlatformBackingStorePrivate;
|
||||
class QPlatformWindow;
|
||||
class QPlatformTextureList;
|
||||
class QPlatformTextureListPrivate;
|
||||
class QOpenGLContext;
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
class Q_GUI_EXPORT QPlatformTextureList : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DECLARE_PRIVATE(QPlatformTextureList)
|
||||
public:
|
||||
explicit QPlatformTextureList(QObject *parent = 0);
|
||||
~QPlatformTextureList();
|
||||
|
||||
int count() const;
|
||||
GLuint textureId(int index) const;
|
||||
QRect geometry(int index) const;
|
||||
void lock(bool on);
|
||||
bool isLocked() const;
|
||||
|
||||
void appendTexture(GLuint textureId, const QRect &geometry);
|
||||
|
||||
Q_SIGNALS:
|
||||
void locked(bool);
|
||||
};
|
||||
#endif
|
||||
|
||||
class Q_GUI_EXPORT QPlatformBackingStore
|
||||
{
|
||||
@ -79,6 +106,11 @@ public:
|
||||
// 'window' can be a child window, in which case 'region' is in child window coordinates and
|
||||
// offset is the (child) window's offset in relation to the window surface.
|
||||
virtual void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) = 0;
|
||||
#ifndef QT_NO_OPENGL
|
||||
virtual void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, QPlatformTextureList *textures, QOpenGLContext *context);
|
||||
virtual QImage toImage() const;
|
||||
virtual GLuint toTexture(const QRegion &dirtyRegion) const;
|
||||
#endif
|
||||
|
||||
virtual void resize(const QSize &size, const QRegion &staticContents) = 0;
|
||||
|
||||
|
@ -328,7 +328,7 @@ QGLXContext::~QGLXContext()
|
||||
bool QGLXContext::makeCurrent(QPlatformSurface *surface)
|
||||
{
|
||||
bool success = false;
|
||||
Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
|
||||
Q_ASSERT(surface->surface()->supportsOpenGL());
|
||||
|
||||
Display *dpy = DISPLAY_FROM_XCB(m_screen);
|
||||
GLXDrawable glxDrawable = 0;
|
||||
|
@ -280,6 +280,11 @@ void QXcbBackingStore::beginPaint(const QRegion ®ion)
|
||||
}
|
||||
}
|
||||
|
||||
QImage QXcbBackingStore::toImage() const
|
||||
{
|
||||
return m_image && m_image->image() ? *m_image->image() : QImage();
|
||||
}
|
||||
|
||||
void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset)
|
||||
{
|
||||
if (!m_image || m_image->size().isEmpty())
|
||||
@ -319,6 +324,25 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
||||
QPlatformTextureList *textures, QOpenGLContext *context)
|
||||
{
|
||||
QPlatformBackingStore::composeAndFlush(window, region, offset, textures, context);
|
||||
|
||||
Q_XCB_NOOP(connection());
|
||||
|
||||
if (m_syncingResize) {
|
||||
QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle());
|
||||
connection()->sync();
|
||||
m_syncingResize = false;
|
||||
platformWindow->updateSyncRequestCounter();
|
||||
} else {
|
||||
xcb_flush(xcb_connection());
|
||||
}
|
||||
}
|
||||
#endif // QT_NO_OPENGL
|
||||
|
||||
void QXcbBackingStore::resize(const QSize &size, const QRegion &)
|
||||
{
|
||||
if (m_image && size == m_image->size())
|
||||
|
@ -60,6 +60,11 @@ public:
|
||||
|
||||
QPaintDevice *paintDevice();
|
||||
void flush(QWindow *window, const QRegion ®ion, const QPoint &offset);
|
||||
#ifndef QT_NO_OPENGL
|
||||
void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset,
|
||||
QPlatformTextureList *textures, QOpenGLContext *context);
|
||||
#endif
|
||||
QImage toImage() const;
|
||||
void resize(const QSize &size, const QRegion &staticContents);
|
||||
bool scroll(const QRegion &area, int dx, int dy);
|
||||
|
||||
|
@ -284,6 +284,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
|
||||
case MultipleWindows: return true;
|
||||
case ForeignWindows: return true;
|
||||
case SyncState: return true;
|
||||
case RasterGLSurface: return true;
|
||||
default: return QPlatformIntegration::hasCapability(cap);
|
||||
}
|
||||
}
|
||||
|
@ -292,8 +292,6 @@ void QXcbWindow::create()
|
||||
if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) {
|
||||
#if defined(XCB_USE_GLX)
|
||||
XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), &m_format);
|
||||
if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
|
||||
qFatal("Could not initialize GLX");
|
||||
#elif defined(XCB_USE_EGL)
|
||||
EGLDisplay eglDisplay = connection()->egl_display();
|
||||
EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, m_format, true);
|
||||
@ -308,9 +306,14 @@ void QXcbWindow::create()
|
||||
XVisualInfo *visualInfo;
|
||||
int matchingCount = 0;
|
||||
visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount);
|
||||
if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
|
||||
qFatal("Could not initialize EGL");
|
||||
#endif //XCB_USE_GLX
|
||||
if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
|
||||
qFatal("Could not initialize OpenGL");
|
||||
|
||||
if (!visualInfo && window()->surfaceType() == QSurface::RasterGLSurface) {
|
||||
qWarning("Could not initialize OpenGL for RasterGLSurface, reverting to RasterSurface.");
|
||||
window()->setSurfaceType(QSurface::RasterSurface);
|
||||
}
|
||||
if (visualInfo) {
|
||||
m_depth = visualInfo->depth;
|
||||
m_imageFormat = imageFormatForDepth(m_depth);
|
||||
|
@ -79,3 +79,8 @@ wince*: {
|
||||
SOURCES += \
|
||||
kernel/qwidgetsfunctions_wince.cpp
|
||||
}
|
||||
|
||||
contains(QT_CONFIG, opengl) {
|
||||
HEADERS += kernel/qopenglwidget_p.h
|
||||
SOURCES += kernel/qopenglwidget.cpp
|
||||
}
|
||||
|
183
src/widgets/kernel/qopenglwidget.cpp
Normal file
183
src/widgets/kernel/qopenglwidget.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the QtWidgets module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qopenglwidget_p.h"
|
||||
#include <QOpenGLContext>
|
||||
#include <QtWidgets/private/qwidget_p.h>
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QWindow>
|
||||
#include <qpa/qplatformwindow.h>
|
||||
#include <QDebug>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QScreen>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QOpenGLWidgetPrivate : public QWidgetPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QOpenGLWidget)
|
||||
public:
|
||||
QOpenGLWidgetPrivate()
|
||||
: fbo(0), uninitialized(true)
|
||||
{
|
||||
setRenderToTexture();
|
||||
}
|
||||
GLuint textureId() const { return fbo ? fbo->texture() : 0; }
|
||||
|
||||
const QSurface *surface() const { return q_func()->window()->windowHandle(); }
|
||||
QSurface *surface() { return q_func()->window()->windowHandle(); }
|
||||
void initialize();
|
||||
|
||||
QOpenGLContext context;
|
||||
QOpenGLFramebufferObject *fbo;
|
||||
bool uninitialized;
|
||||
|
||||
int w,h;
|
||||
};
|
||||
|
||||
void QOpenGLWidgetPrivate::initialize()
|
||||
{
|
||||
Q_Q(QOpenGLWidget);
|
||||
if (!uninitialized)
|
||||
return;
|
||||
context.setShareContext(get(q->window())->shareContext());
|
||||
context.setFormat(surface()->format());
|
||||
context.create();
|
||||
context.makeCurrent(surface());
|
||||
q->initializeGL();
|
||||
uninitialized = false;
|
||||
}
|
||||
|
||||
QOpenGLWidget::QOpenGLWidget(QWidget *parent, Qt::WindowFlags f)
|
||||
: QWidget(*(new QOpenGLWidgetPrivate), parent, f)
|
||||
{
|
||||
}
|
||||
|
||||
QOpenGLWidget::~QOpenGLWidget()
|
||||
{
|
||||
}
|
||||
|
||||
bool QOpenGLWidget::isValid() const
|
||||
{
|
||||
Q_D(const QOpenGLWidget);
|
||||
return d->context.isValid();
|
||||
}
|
||||
|
||||
void QOpenGLWidget::makeCurrent()
|
||||
{
|
||||
Q_D(QOpenGLWidget);
|
||||
d->context.makeCurrent(d->surface());
|
||||
d->fbo->bind();
|
||||
}
|
||||
|
||||
void QOpenGLWidget::doneCurrent()
|
||||
{
|
||||
Q_D(QOpenGLWidget);
|
||||
d->context.doneCurrent();
|
||||
}
|
||||
|
||||
QSurfaceFormat QOpenGLWidget::format() const
|
||||
{
|
||||
Q_D(const QOpenGLWidget);
|
||||
return d->surface()->format();
|
||||
}
|
||||
|
||||
GLuint QOpenGLWidget::defaultFramebufferObject() const
|
||||
{
|
||||
Q_D(const QOpenGLWidget);
|
||||
return d->fbo ? d->fbo->handle() : 0;
|
||||
}
|
||||
|
||||
void QOpenGLWidget::initializeGL()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void QOpenGLWidget::resizeGL(int w, int h)
|
||||
{
|
||||
Q_UNUSED(w);
|
||||
Q_UNUSED(h);
|
||||
}
|
||||
|
||||
void QOpenGLWidget::paintGL()
|
||||
{
|
||||
}
|
||||
|
||||
void QOpenGLWidget::updateGL()
|
||||
{
|
||||
makeCurrent();
|
||||
paintGL();
|
||||
glFlush();
|
||||
doneCurrent();
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void QOpenGLWidget::resizeEvent(QResizeEvent *)
|
||||
{
|
||||
Q_D(QOpenGLWidget);
|
||||
d->w = width();
|
||||
d->h = height();
|
||||
d->initialize();
|
||||
|
||||
d->context.makeCurrent(d->surface());
|
||||
delete d->fbo; // recreate when resized
|
||||
d->fbo = new QOpenGLFramebufferObject(size());
|
||||
d->fbo->bind();
|
||||
glBindTexture(GL_TEXTURE_2D, d->fbo->texture());
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
resizeGL(width(), height());
|
||||
paintGL();
|
||||
glFlush();
|
||||
}
|
||||
|
||||
void QOpenGLWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
qWarning("QOpenGLWidget does not support paintEvent() yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
135
src/widgets/kernel/qopenglwidget_p.h
Normal file
135
src/widgets/kernel/qopenglwidget_p.h
Normal file
@ -0,0 +1,135 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the QtWidgets module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It may change from version to version
|
||||
// without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
#ifndef QOPENGLWIDGET_H
|
||||
#define QOPENGLWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QSurfaceFormat>
|
||||
|
||||
#include <QtGui/qopengl.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QOpenGLWidgetPrivate;
|
||||
|
||||
class Q_WIDGETS_EXPORT QOpenGLWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DECLARE_PRIVATE(QOpenGLWidget)
|
||||
|
||||
public:
|
||||
explicit QOpenGLWidget(QWidget* parent=0,
|
||||
Qt::WindowFlags f=0);
|
||||
|
||||
// This API is not finalized yet. The commented-out functions below are
|
||||
// QGLWidget functions that have not been implemented for QOpenGLWidget.
|
||||
// Some of them may not end up in the final version (which is planned for a
|
||||
// future release of Qt).
|
||||
|
||||
// explicit QOpenGLWidget(const QSurfaceFormat& format, QWidget* parent=0,
|
||||
// Qt::WindowFlags f=0);
|
||||
~QOpenGLWidget();
|
||||
|
||||
// void qglClearColor(const QColor& c) const;
|
||||
|
||||
bool isValid() const;
|
||||
// bool isSharing() const;
|
||||
|
||||
void makeCurrent();
|
||||
void doneCurrent();
|
||||
|
||||
// void swapBuffers();
|
||||
|
||||
QSurfaceFormat format() const;
|
||||
GLuint defaultFramebufferObject() const;
|
||||
|
||||
// QPixmap renderPixmap(int w = 0, int h = 0, bool useContext = false);
|
||||
QImage grabFrameBuffer(bool withAlpha = false);
|
||||
|
||||
// static QImage convertToGLFormat(const QImage& img);
|
||||
|
||||
// QPaintEngine *paintEngine() const;
|
||||
|
||||
// void drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget = GL_TEXTURE_2D);
|
||||
// void drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget = GL_TEXTURE_2D);
|
||||
|
||||
public Q_SLOTS:
|
||||
void updateGL();
|
||||
|
||||
protected:
|
||||
// bool event(QEvent *);
|
||||
virtual void initializeGL();
|
||||
virtual void resizeGL(int w, int h);
|
||||
virtual void paintGL();
|
||||
|
||||
// void setAutoBufferSwap(bool on);
|
||||
// bool autoBufferSwap() const;
|
||||
|
||||
void paintEvent(QPaintEvent*);
|
||||
void resizeEvent(QResizeEvent*);
|
||||
|
||||
// virtual void glInit();
|
||||
// virtual void glDraw();
|
||||
|
||||
// QOpenGLWidget(QOpenGLWidgetPrivate &dd,
|
||||
// const QGLFormat &format = QGLFormat(),
|
||||
// QWidget *parent = 0,
|
||||
// const QOpenGLWidget* shareWidget = 0,
|
||||
// Qt::WindowFlags f = 0);
|
||||
private:
|
||||
Q_DISABLE_COPY(QOpenGLWidget)
|
||||
|
||||
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QOPENGLWIDGET_H
|
@ -78,6 +78,7 @@
|
||||
#include "private/qstyle_p.h"
|
||||
#include "qfileinfo.h"
|
||||
#include <QtGui/qinputmethod.h>
|
||||
#include <QtGui/qopenglcontext.h>
|
||||
|
||||
#include <private/qgraphicseffect_p.h>
|
||||
#include <qbackingstore.h>
|
||||
@ -270,6 +271,8 @@ QWidgetPrivate::QWidgetPrivate(int version)
|
||||
, isMoved(0)
|
||||
, usesDoubleBufferedGLContext(0)
|
||||
, mustHaveWindowHandle(0)
|
||||
, renderToTexture(0)
|
||||
, textureChildSeen(0)
|
||||
#ifndef QT_NO_IM
|
||||
, inheritsInputMethodHints(0)
|
||||
#endif
|
||||
@ -1558,6 +1561,7 @@ void QWidgetPrivate::createTLExtra()
|
||||
x->inRepaint = false;
|
||||
x->embedded = 0;
|
||||
x->window = 0;
|
||||
x->shareContext = 0;
|
||||
x->screenIndex = 0;
|
||||
#ifdef Q_WS_MAC
|
||||
x->wasMaximized = false;
|
||||
@ -5133,9 +5137,17 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
|
||||
<< "geometry ==" << QRect(q->mapTo(q->window(), QPoint(0, 0)), q->size());
|
||||
#endif
|
||||
|
||||
if (renderToTexture) {
|
||||
// This widget renders into a texture which is composed later. We just need to
|
||||
// punch a hole in the backingstore, so the texture will be visible.
|
||||
QPainter p(q);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.fillRect(q->rect(), Qt::transparent);
|
||||
} else {
|
||||
//actually send the paint event
|
||||
QPaintEvent e(toBePainted);
|
||||
QCoreApplication::sendSpontaneousEvent(q, &e);
|
||||
}
|
||||
|
||||
// Native widgets need to be marked dirty on screen so painting will be done in correct context
|
||||
if (backingStore && !onScreen && !asRoot && (q->internalWinId() || !q->nativeParentWidget()->isWindow()))
|
||||
@ -9637,6 +9649,13 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
|
||||
if (desktopWidget)
|
||||
parent = 0;
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
if (d->textureChildSeen && parent) {
|
||||
// set the textureChildSeen flag up the whole parent chain
|
||||
QWidgetPrivate::get(parent)->setTextureChildSeen();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (QWidgetBackingStore *oldBs = oldtlw->d_func()->maybeBackingStore()) {
|
||||
if (newParent)
|
||||
oldBs->removeDirtyWidget(this);
|
||||
@ -11108,7 +11127,25 @@ void QWidgetPrivate::adjustQuitOnCloseAttribute()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QOpenGLContext *QWidgetPrivate::shareContext() const
|
||||
{
|
||||
#ifdef QT_NO_OPENGL
|
||||
return 0;
|
||||
#else
|
||||
if (!extra || !extra->topextra || !extra->topextra->window) {
|
||||
qWarning() << "Asking for share context for widget that does not have a window handle";
|
||||
return 0;
|
||||
}
|
||||
QWidgetPrivate *that = const_cast<QWidgetPrivate *>(this);
|
||||
if (!extra->topextra->shareContext) {
|
||||
QOpenGLContext *ctx = new QOpenGLContext();
|
||||
ctx->setFormat(extra->topextra->window->format());
|
||||
ctx->create();
|
||||
that->extra->topextra->shareContext = ctx;
|
||||
}
|
||||
return that->extra->topextra->shareContext;
|
||||
#endif // QT_NO_OPENGL
|
||||
}
|
||||
|
||||
Q_WIDGETS_EXPORT QWidgetData *qt_qwidget_data(QWidget *widget)
|
||||
{
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include "QtCore/qset.h"
|
||||
#include "QtGui/qregion.h"
|
||||
#include "QtGui/qinputmethod.h"
|
||||
#include "QtGui/qopengl.h"
|
||||
#include "QtWidgets/qsizepolicy.h"
|
||||
#include "QtWidgets/qstyle.h"
|
||||
#include "QtWidgets/qapplication.h"
|
||||
@ -80,6 +81,7 @@ class QPixmap;
|
||||
class QWidgetBackingStore;
|
||||
class QGraphicsProxyWidget;
|
||||
class QWidgetItemV2;
|
||||
class QOpenGLContext;
|
||||
|
||||
class QStyle;
|
||||
|
||||
@ -216,6 +218,7 @@ struct QTLWExtra {
|
||||
bool wasMaximized;
|
||||
#endif
|
||||
QWidgetWindow *window;
|
||||
QOpenGLContext *shareContext;
|
||||
quint32 screenIndex; // index in qplatformscreenlist
|
||||
};
|
||||
|
||||
@ -324,6 +327,8 @@ public:
|
||||
explicit QWidgetPrivate(int version = QObjectPrivateVersion);
|
||||
~QWidgetPrivate();
|
||||
|
||||
static QWidgetPrivate *get(QWidget *w) { return w->d_func(); }
|
||||
|
||||
QWExtra *extraData() const;
|
||||
QTLWExtra *topData() const;
|
||||
QTLWExtra *maybeTopData() const;
|
||||
@ -618,6 +623,27 @@ public:
|
||||
inline QRect mapFromWS(const QRect &r) const
|
||||
{ QRect rr(r); rr.translate(data.wrect.topLeft()); return rr; }
|
||||
|
||||
QOpenGLContext *shareContext() const;
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
virtual GLuint textureId() const { return 0; }
|
||||
|
||||
void setRenderToTexture() { renderToTexture = true; textureChildSeen = true; }
|
||||
void setTextureChildSeen()
|
||||
{
|
||||
Q_Q(QWidget);
|
||||
if (textureChildSeen)
|
||||
return;
|
||||
textureChildSeen = 1;
|
||||
|
||||
if (!q->isWindow()) {
|
||||
QWidget *parent = q->parentWidget();
|
||||
if (parent)
|
||||
get(parent)->setTextureChildSeen();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Variables.
|
||||
// Regular pointers (keep them together to avoid gaps on 64 bit architectures).
|
||||
QWExtra *extra;
|
||||
@ -698,6 +724,8 @@ public:
|
||||
uint isMoved : 1;
|
||||
uint usesDoubleBufferedGLContext : 1;
|
||||
uint mustHaveWindowHandle : 1;
|
||||
uint renderToTexture : 1;
|
||||
uint textureChildSeen : 1;
|
||||
#ifndef QT_NO_IM
|
||||
uint inheritsInputMethodHints : 1;
|
||||
#endif
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "QtWidgets/qdesktopwidget.h"
|
||||
#include <qpa/qplatformwindow.h>
|
||||
#include "QtGui/qsurfaceformat.h"
|
||||
#include <QtGui/qopenglcontext.h>
|
||||
#include <qpa/qplatformopenglcontext.h>
|
||||
#include <qpa/qplatformintegration.h>
|
||||
#include "QtGui/private/qwindow_p.h"
|
||||
@ -953,6 +954,10 @@ void QWidgetPrivate::deleteTLSysExtra()
|
||||
delete extra->topextra->backingStore;
|
||||
extra->topextra->backingStore = 0;
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
delete extra->topextra->shareContext;
|
||||
extra->topextra->shareContext = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,8 @@
|
||||
#include <private/qpaintengine_raster_p.h>
|
||||
#include <private/qgraphicseffect_p.h>
|
||||
|
||||
#include <qpa/qplatformbackingstore.h>
|
||||
|
||||
#if defined(Q_OS_WIN) && !defined(QT_NO_PAINT_DEBUG)
|
||||
# include <QtCore/qt_windows.h>
|
||||
# include <qpa/qplatformnativeinterface.h>
|
||||
@ -72,10 +74,15 @@ extern QRegion qt_dirtyRegion(QWidget *);
|
||||
* \a region is the region to be updated in \a widget coordinates.
|
||||
*/
|
||||
static inline void qt_flush(QWidget *widget, const QRegion ®ion, QBackingStore *backingStore,
|
||||
QWidget *tlw, const QPoint &tlwOffset)
|
||||
QWidget *tlw, const QPoint &tlwOffset, QPlatformTextureList *widgetTextures = 0,
|
||||
QOpenGLContext *context = 0)
|
||||
{
|
||||
#ifdef QT_NO_OPENGL
|
||||
Q_UNUSED(widgetTextures);
|
||||
Q_UNUSED(context);
|
||||
#endif
|
||||
Q_ASSERT(widget);
|
||||
Q_ASSERT(!region.isEmpty());
|
||||
Q_ASSERT(!region.isEmpty() || (context && widgetTextures && widgetTextures->count()));
|
||||
Q_ASSERT(backingStore);
|
||||
Q_ASSERT(tlw);
|
||||
|
||||
@ -104,10 +111,16 @@ static inline void qt_flush(QWidget *widget, const QRegion ®ion, QBackingStor
|
||||
if (tlw->testAttribute(Qt::WA_DontShowOnScreen) || widget->testAttribute(Qt::WA_DontShowOnScreen))
|
||||
return;
|
||||
|
||||
QPoint offset = tlwOffset;
|
||||
if (widget != tlw)
|
||||
backingStore->flush(region, widget->windowHandle(), tlwOffset + widget->mapTo(tlw, QPoint()));
|
||||
offset += widget->mapTo(tlw, QPoint());
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
if (widgetTextures)
|
||||
backingStore->handle()->composeAndFlush(widget->windowHandle(), region, offset, widgetTextures, context);
|
||||
else
|
||||
backingStore->flush(region, widget->windowHandle(), tlwOffset);
|
||||
#endif
|
||||
backingStore->flush(region, widget->windowHandle(), offset);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_PAINT_DEBUG
|
||||
@ -430,7 +443,7 @@ QRegion QWidgetBackingStore::staticContents(QWidget *parent, const QRect &within
|
||||
return region;
|
||||
}
|
||||
|
||||
static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
|
||||
void QWidgetBackingStore::sendUpdateRequest(QWidget *widget, bool updateImmediately)
|
||||
{
|
||||
if (!widget)
|
||||
return;
|
||||
@ -439,6 +452,7 @@ static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
|
||||
QEvent event(QEvent::UpdateRequest);
|
||||
QApplication::sendEvent(widget, &event);
|
||||
} else {
|
||||
updateRequestSent = true;
|
||||
QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
|
||||
}
|
||||
}
|
||||
@ -488,6 +502,7 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
|
||||
return;
|
||||
}
|
||||
|
||||
//### FIXME fullUpdatePending seems to be always false????
|
||||
if (fullUpdatePending) {
|
||||
if (updateImmediately)
|
||||
sendUpdateRequest(tlw, updateImmediately);
|
||||
@ -495,6 +510,13 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
|
||||
}
|
||||
|
||||
const QPoint offset = widget->mapTo(tlw, QPoint());
|
||||
|
||||
if (QWidgetPrivate::get(widget)->renderToTexture) {
|
||||
if (!updateRequestSent || updateImmediately)
|
||||
sendUpdateRequest(tlw, updateImmediately);
|
||||
return;
|
||||
}
|
||||
|
||||
const QRect widgetRect = widget->d_func()->effectiveRectFor(widget->rect());
|
||||
if (qt_region_strictContains(dirty, widgetRect.translated(offset))) {
|
||||
if (updateImmediately)
|
||||
@ -503,7 +525,7 @@ void QWidgetBackingStore::markDirty(const QRegion &rgn, QWidget *widget, bool up
|
||||
}
|
||||
|
||||
if (invalidateBuffer) {
|
||||
const bool eventAlreadyPosted = !dirty.isEmpty();
|
||||
const bool eventAlreadyPosted = !dirty.isEmpty() || updateRequestSent;
|
||||
#ifndef QT_NO_GRAPHICSEFFECT
|
||||
if (widget->d_func()->graphicsEffect)
|
||||
dirty += widget->d_func()->effectiveRectFor(rgn.boundingRect()).translated(offset);
|
||||
@ -583,6 +605,13 @@ void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool upd
|
||||
return;
|
||||
}
|
||||
|
||||
if (QWidgetPrivate::get(widget)->renderToTexture) {
|
||||
if (!updateRequestSent || updateImmediately)
|
||||
sendUpdateRequest(tlw, updateImmediately);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const QRect widgetRect = widget->d_func()->effectiveRectFor(rect);
|
||||
const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
|
||||
if (qt_region_strictContains(dirty, translatedRect)) {
|
||||
@ -703,7 +732,11 @@ void QWidgetBackingStore::updateLists(QWidget *cur)
|
||||
}
|
||||
|
||||
QWidgetBackingStore::QWidgetBackingStore(QWidget *topLevel)
|
||||
: tlw(topLevel), dirtyOnScreenWidgets(0), fullUpdatePending(0)
|
||||
: tlw(topLevel),
|
||||
dirtyOnScreenWidgets(0),
|
||||
widgetTextures(0),
|
||||
fullUpdatePending(0),
|
||||
updateRequestSent(0)
|
||||
{
|
||||
store = tlw->backingStore();
|
||||
Q_ASSERT(store);
|
||||
@ -902,7 +935,7 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg
|
||||
|
||||
// Nothing to repaint.
|
||||
if (!isDirty()) {
|
||||
qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset);
|
||||
qt_flush(exposedWidget, exposedRegion, store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -914,11 +947,27 @@ void QWidgetBackingStore::sync(QWidget *exposedWidget, const QRegion &exposedReg
|
||||
doSync();
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
static void findTextureWidgetsRecursively(QWidget *tlw, QWidget *widget, QPlatformTextureList *widgetTextures)
|
||||
{
|
||||
QWidgetPrivate *wd = QWidgetPrivate::get(widget);
|
||||
if (wd->renderToTexture)
|
||||
widgetTextures->appendTexture(wd->textureId(), QRect(widget->mapTo(tlw, QPoint()), widget->size()));
|
||||
|
||||
for (int i = 0; i < wd->children.size(); ++i) {
|
||||
QWidget *w = qobject_cast<QWidget *>(wd->children.at(i));
|
||||
if (w && !w->isWindow() && !w->isHidden() && QWidgetPrivate::get(w)->textureChildSeen)
|
||||
findTextureWidgetsRecursively(tlw, w, widgetTextures);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Synchronizes the backing store, i.e. dirty areas are repainted and flushed.
|
||||
*/
|
||||
void QWidgetBackingStore::sync()
|
||||
{
|
||||
updateRequestSent = false;
|
||||
QTLWExtra *tlwExtra = tlw->d_func()->maybeTopData();
|
||||
if (discardSyncRequest(tlw, tlwExtra)) {
|
||||
// If the top-level is minimized, it's not visible on the screen so we can delay the
|
||||
@ -1024,7 +1073,15 @@ void QWidgetBackingStore::doSync()
|
||||
}
|
||||
dirtyWidgets.clear();
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
delete widgetTextures;
|
||||
widgetTextures = 0;
|
||||
if (tlw->d_func()->textureChildSeen) {
|
||||
widgetTextures = new QPlatformTextureList; // TODO: implement support for locking
|
||||
findTextureWidgetsRecursively(tlw, tlw, widgetTextures);
|
||||
}
|
||||
fullUpdatePending = false;
|
||||
#endif
|
||||
|
||||
if (toClean.isEmpty()) {
|
||||
// Nothing to repaint. However, we might have newly exposed areas on the
|
||||
@ -1038,6 +1095,7 @@ void QWidgetBackingStore::doSync()
|
||||
if (tlw->d_func()->extra->proxyWidget) {
|
||||
updateStaticContentsSize();
|
||||
dirty = QRegion();
|
||||
updateRequestSent = false;
|
||||
const QVector<QRect> rects(toClean.rects());
|
||||
for (int i = 0; i < rects.size(); ++i)
|
||||
tlw->d_func()->extra->proxyWidget->update(rects.at(i));
|
||||
@ -1051,6 +1109,7 @@ void QWidgetBackingStore::doSync()
|
||||
for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i)
|
||||
resetWidget(opaqueNonOverlappedWidgets[i]);
|
||||
dirty = QRegion();
|
||||
updateRequestSent = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1059,6 +1118,7 @@ void QWidgetBackingStore::doSync()
|
||||
updateStaticContentsSize();
|
||||
const QRegion dirtyCopy(dirty);
|
||||
dirty = QRegion();
|
||||
updateRequestSent = false;
|
||||
|
||||
// Paint opaque non overlapped widgets.
|
||||
for (int i = 0; i < opaqueNonOverlappedWidgets.size(); ++i) {
|
||||
@ -1099,12 +1159,19 @@ void QWidgetBackingStore::flush(QWidget *widget)
|
||||
{
|
||||
if (!dirtyOnScreen.isEmpty()) {
|
||||
QWidget *target = widget ? widget : tlw;
|
||||
qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset);
|
||||
qt_flush(target, dirtyOnScreen, store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext());
|
||||
dirtyOnScreen = QRegion();
|
||||
}
|
||||
|
||||
if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty())
|
||||
if (!dirtyOnScreenWidgets || dirtyOnScreenWidgets->isEmpty()) {
|
||||
#ifndef QT_NO_OPENGL
|
||||
if (widgetTextures && widgetTextures->count()) {
|
||||
QWidget *target = widget ? widget : tlw;
|
||||
qt_flush(target, QRegion(), store, tlw, tlwOffset, widgetTextures, tlw->d_func()->shareContext());
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dirtyOnScreenWidgets->size(); ++i) {
|
||||
QWidget *w = dirtyOnScreenWidgets->at(i);
|
||||
|
@ -60,6 +60,8 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QPlatformTextureList;
|
||||
|
||||
struct BeginPaintInfo {
|
||||
inline BeginPaintInfo() : wasFlushed(0), nothingToPaint(0), backingStoreRecreated(0) {}
|
||||
uint wasFlushed : 1;
|
||||
@ -102,11 +104,15 @@ private:
|
||||
QVector<QWidget *> dirtyWidgets;
|
||||
QVector<QWidget *> *dirtyOnScreenWidgets;
|
||||
QList<QWidget *> staticWidgets;
|
||||
QPlatformTextureList *widgetTextures;
|
||||
QBackingStore *store;
|
||||
uint fullUpdatePending : 1;
|
||||
uint updateRequestSent : 1;
|
||||
|
||||
QPoint tlwOffset;
|
||||
|
||||
void sendUpdateRequest(QWidget *widget, bool updateImmediately);
|
||||
|
||||
static bool flushPaint(QWidget *widget, const QRegion &rgn);
|
||||
static void unflushPaint(QWidget *widget, const QRegion &rgn);
|
||||
|
||||
|
@ -92,6 +92,12 @@ QWidgetWindow::QWidgetWindow(QWidget *widget)
|
||||
, m_widget(widget)
|
||||
{
|
||||
updateObjectName();
|
||||
// Enable QOpenGLWidget/QQuickWidget children if the platform plugin supports it,
|
||||
// and the application developer has not explicitly disabled it.
|
||||
if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RasterGLSurface)
|
||||
&& !QApplication::testAttribute(Qt::AA_ForceRasterWidgets)) {
|
||||
setSurfaceType(QSurface::RasterGLSurface);
|
||||
}
|
||||
connect(m_widget, &QObject::objectNameChanged, this, &QWidgetWindow::updateObjectName);
|
||||
}
|
||||
|
||||
|
73
tests/manual/qopenglwidget/openglwidget/main.cpp
Normal file
73
tests/manual/qopenglwidget/openglwidget/main.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "openglwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QPushButton>
|
||||
#include <QMdiArea>
|
||||
#include <QLCDNumber>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
|
||||
QMdiArea w;
|
||||
w.resize(400,400);
|
||||
|
||||
OpenGLWidget *glw = new OpenGLWidget;
|
||||
w.addSubWindow(glw);
|
||||
glw->setMinimumSize(100,100);
|
||||
|
||||
OpenGLWidget *glw2 = new OpenGLWidget;
|
||||
glw2->setMinimumSize(100,100);
|
||||
w.addSubWindow(glw2);
|
||||
|
||||
QLCDNumber *lcd = new QLCDNumber;
|
||||
lcd->display(1337);
|
||||
lcd->setMinimumSize(300,100);
|
||||
w.addSubWindow(lcd);
|
||||
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
193
tests/manual/qopenglwidget/openglwidget/openglwidget.cpp
Normal file
193
tests/manual/qopenglwidget/openglwidget/openglwidget.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
|
||||
#include "openglwidget.h"
|
||||
#include <QtWidgets/private/qwidget_p.h>
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QWindow>
|
||||
#include <qpa/qplatformwindow.h>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
|
||||
#include <QtGui/QOpenGLFunctions>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QMatrix4x4>
|
||||
#include <QtGui/QOpenGLShaderProgram>
|
||||
#include <QtGui/QScreen>
|
||||
|
||||
#include <QtCore/qmath.h>
|
||||
#include <qopengl.h>
|
||||
|
||||
#include <GL/glext.h>
|
||||
|
||||
class OpenGLWidgetPrivate
|
||||
{
|
||||
public:
|
||||
OpenGLWidgetPrivate()
|
||||
: m_program(0), m_frame(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void initialize();
|
||||
void render();
|
||||
|
||||
|
||||
int width() {return w;}
|
||||
int height() {return h;}
|
||||
|
||||
GLuint m_posAttr;
|
||||
GLuint m_colAttr;
|
||||
GLuint m_matrixUniform;
|
||||
|
||||
QOpenGLShaderProgram *m_program;
|
||||
int m_frame;
|
||||
|
||||
int w,h;
|
||||
};
|
||||
|
||||
|
||||
OpenGLWidget::OpenGLWidget(QWidget *parent)
|
||||
: QOpenGLWidget(parent)
|
||||
{
|
||||
d = new OpenGLWidgetPrivate;
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(updateGL()));
|
||||
timer->start(30);
|
||||
}
|
||||
|
||||
OpenGLWidget::~OpenGLWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OpenGLWidget::initializeGL()
|
||||
{
|
||||
// qDebug("*initializeGL*");
|
||||
d->initialize();
|
||||
}
|
||||
|
||||
void OpenGLWidget::resizeGL(int w, int h)
|
||||
{
|
||||
// qDebug("*resizeGL*");
|
||||
d->w = w;
|
||||
d->h = h;
|
||||
}
|
||||
void OpenGLWidget::paintGL()
|
||||
{
|
||||
// qDebug("*paintGL* %d", d->m_frame);
|
||||
d->render();
|
||||
}
|
||||
|
||||
|
||||
static const char *vertexShaderSource =
|
||||
"attribute highp vec4 posAttr;\n"
|
||||
"attribute lowp vec4 colAttr;\n"
|
||||
"varying lowp vec4 col;\n"
|
||||
"uniform highp mat4 matrix;\n"
|
||||
"void main() {\n"
|
||||
" col = colAttr;\n"
|
||||
" gl_Position = matrix * posAttr;\n"
|
||||
"}\n";
|
||||
|
||||
static const char *fragmentShaderSource =
|
||||
"varying lowp vec4 col;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = col;\n"
|
||||
"}\n";
|
||||
|
||||
void OpenGLWidgetPrivate::initialize()
|
||||
{
|
||||
m_program = new QOpenGLShaderProgram;
|
||||
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
|
||||
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
|
||||
m_program->link();
|
||||
m_posAttr = m_program->attributeLocation("posAttr");
|
||||
m_colAttr = m_program->attributeLocation("colAttr");
|
||||
m_matrixUniform = m_program->uniformLocation("matrix");
|
||||
}
|
||||
|
||||
void OpenGLWidgetPrivate::render()
|
||||
{
|
||||
const qreal retinaScale = 1.0;//devicePixelRatio();
|
||||
glViewport(0, 0, width() * retinaScale, height() * retinaScale);
|
||||
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
m_program->bind();
|
||||
|
||||
QMatrix4x4 matrix;
|
||||
matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
|
||||
matrix.translate(0, 0, -2);
|
||||
matrix.rotate(100.0f * m_frame / 30/*screen()->refreshRate()*/, 0, 1, 0);
|
||||
|
||||
m_program->setUniformValue(m_matrixUniform, matrix);
|
||||
|
||||
GLfloat vertices[] = {
|
||||
0.0f, 0.707f,
|
||||
-0.5f, -0.5f,
|
||||
0.5f, -0.5f
|
||||
};
|
||||
|
||||
GLfloat colors[] = {
|
||||
1.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, 0, vertices);
|
||||
glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glDisableVertexAttribArray(1);
|
||||
glDisableVertexAttribArray(0);
|
||||
|
||||
m_program->release();
|
||||
|
||||
++m_frame;
|
||||
}
|
63
tests/manual/qopenglwidget/openglwidget/openglwidget.h
Normal file
63
tests/manual/qopenglwidget/openglwidget/openglwidget.h
Normal file
@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and Digia. For licensing terms and
|
||||
** conditions see http://qt.digia.com/licensing. For further information
|
||||
** use the contact form at http://qt.digia.com/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Digia gives you certain additional
|
||||
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3.0 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU General Public License version 3.0 requirements will be
|
||||
** met: http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef OPENGLWIDGET_H
|
||||
#define OPENGLWIDGET_H
|
||||
|
||||
#include <QtWidgets/private/qopenglwidget_p.h>
|
||||
|
||||
class OpenGLWidgetPrivate;
|
||||
class OpenGLWidget : public QOpenGLWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OpenGLWidget(QWidget *parent = 0);
|
||||
~OpenGLWidget();
|
||||
|
||||
void initializeGL();
|
||||
void resizeGL(int w, int h);
|
||||
void paintGL();
|
||||
|
||||
private:
|
||||
OpenGLWidgetPrivate *d;
|
||||
};
|
||||
|
||||
#endif // OPENGLWIDGET_H
|
9
tests/manual/qopenglwidget/openglwidget/openglwidget.pro
Normal file
9
tests/manual/qopenglwidget/openglwidget/openglwidget.pro
Normal file
@ -0,0 +1,9 @@
|
||||
QT += widgets widgets-private gui-private core-private
|
||||
|
||||
TARGET = openglwidget
|
||||
TEMPLATE = app
|
||||
|
||||
SOURCES += main.cpp \
|
||||
openglwidget.cpp
|
||||
|
||||
HEADERS += openglwidget.h
|
Loading…
Reference in New Issue
Block a user