diff --git a/examples/opengl/hellowindow/hellowindow.cpp b/examples/opengl/hellowindow/hellowindow.cpp index 3c4f88bdfe..cc1f52a92c 100644 --- a/examples/opengl/hellowindow/hellowindow.cpp +++ b/examples/opengl/hellowindow/hellowindow.cpp @@ -1,6 +1,6 @@ #include "hellowindow.h" -#include +#include #include @@ -10,7 +10,7 @@ Renderer::Renderer(const QSurfaceFormat &format, Renderer *share) : m_initialized(false) , m_format(format) { - m_context = new QGuiGLContext; + m_context = new QOpenGLContext; m_context->setFormat(format); if (share) m_context->setShareContext(share->m_context); @@ -91,11 +91,11 @@ void Renderer::render(QSurface *surface, const QColor &color, const QSize &viewS modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f); modelview.translate(0.0f, -0.2f, 0.0f); - program.bind(); - program.setUniformValue(matrixUniform, modelview); - program.setUniformValue(colorUniform, color); + m_program->bind(); + m_program->setUniformValue(matrixUniform, modelview); + m_program->setUniformValue(colorUniform, color); paintQtLogo(); - program.release(); + m_program->release(); glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); @@ -107,20 +107,20 @@ void Renderer::render(QSurface *surface, const QColor &color, const QSize &viewS void Renderer::paintQtLogo() { - program.enableAttributeArray(normalAttr); - program.enableAttributeArray(vertexAttr); - program.setAttributeArray(vertexAttr, vertices.constData()); - program.setAttributeArray(normalAttr, normals.constData()); + m_program->enableAttributeArray(normalAttr); + m_program->enableAttributeArray(vertexAttr); + m_program->setAttributeArray(vertexAttr, vertices.constData()); + m_program->setAttributeArray(normalAttr, normals.constData()); glDrawArrays(GL_TRIANGLES, 0, vertices.size()); - program.disableAttributeArray(normalAttr); - program.disableAttributeArray(vertexAttr); + m_program->disableAttributeArray(normalAttr); + m_program->disableAttributeArray(vertexAttr); } void Renderer::initialize() { glClearColor(0.1f, 0.1f, 0.2f, 1.0f); - QGLShader *vshader = new QGLShader(QGLShader::Vertex, this); + QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this); const char *vsrc = "attribute highp vec4 vertex;\n" "attribute mediump vec3 normal;\n" @@ -138,7 +138,7 @@ void Renderer::initialize() "}\n"; vshader->compileSourceCode(vsrc); - QGLShader *fshader = new QGLShader(QGLShader::Fragment, this); + QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this); const char *fsrc = "varying mediump vec4 color;\n" "void main(void)\n" @@ -147,14 +147,15 @@ void Renderer::initialize() "}\n"; fshader->compileSourceCode(fsrc); - program.addShader(vshader); - program.addShader(fshader); - program.link(); + m_program = new QOpenGLShaderProgram; + m_program->addShader(vshader); + m_program->addShader(fshader); + m_program->link(); - vertexAttr = program.attributeLocation("vertex"); - normalAttr = program.attributeLocation("normal"); - matrixUniform = program.uniformLocation("matrix"); - colorUniform = program.uniformLocation("sourceColor"); + vertexAttr = m_program->attributeLocation("vertex"); + normalAttr = m_program->attributeLocation("normal"); + matrixUniform = m_program->uniformLocation("matrix"); + colorUniform = m_program->uniformLocation("sourceColor"); m_fAngle = 0; createGeometry(); diff --git a/examples/opengl/hellowindow/hellowindow.h b/examples/opengl/hellowindow/hellowindow.h index c114b09a24..6ff7411251 100644 --- a/examples/opengl/hellowindow/hellowindow.h +++ b/examples/opengl/hellowindow/hellowindow.h @@ -1,12 +1,12 @@ #include -#include -#include -#include +#include +#include +#include #include -class QGuiGLContext; +class QOpenGLContext; class Renderer : public QObject { @@ -31,7 +31,6 @@ private: void extrude(qreal x1, qreal y1, qreal x2, qreal y2); QVector vertices; QVector normals; - QGLShaderProgram program; int vertexAttr; int normalAttr; int matrixUniform; @@ -39,7 +38,8 @@ private: bool m_initialized; QSurfaceFormat m_format; - QGuiGLContext *m_context; + QOpenGLContext *m_context; + QOpenGLShaderProgram *m_program; }; class HelloWindow : public QWindow diff --git a/examples/opengl/hellowindow/hellowindow.pro b/examples/opengl/hellowindow/hellowindow.pro index 44003d8863..555dc83574 100644 --- a/examples/opengl/hellowindow/hellowindow.pro +++ b/examples/opengl/hellowindow/hellowindow.pro @@ -6,8 +6,6 @@ TEMPLATE = app DEPENDPATH += . INCLUDEPATH += . -QT += opengl widgets - # Input HEADERS += hellowindow.h SOURCES += hellowindow.cpp main.cpp diff --git a/examples/opengl/opengl.pro b/examples/opengl/opengl.pro index 59ba7b8bd5..5502ee270a 100644 --- a/examples/opengl/opengl.pro +++ b/examples/opengl/opengl.pro @@ -24,6 +24,7 @@ contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2){ qpa { SUBDIRS += hellowindow + SUBDIRS += paintedwindow } # install diff --git a/examples/opengl/paintedwindow/main.cpp b/examples/opengl/paintedwindow/main.cpp new file mode 100644 index 0000000000..c77cf41f0f --- /dev/null +++ b/examples/opengl/paintedwindow/main.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +#include "paintedwindow.h" + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + QScreen *screen = QGuiApplication::primaryScreen(); + + QRect screenGeometry = screen->availableGeometry(); + + QSurfaceFormat format; + format.setDepthBufferSize(16); + format.setSamples(4); + + QPoint center = screenGeometry.center(); + QRect windowRect(0, 0, 640, 480); + + PaintedWindow window; + window.setGeometry(QRect(center - windowRect.center(), windowRect.size())); + window.show(); + + app.exec(); +} diff --git a/examples/opengl/paintedwindow/paintedwindow.cpp b/examples/opengl/paintedwindow/paintedwindow.cpp new file mode 100644 index 0000000000..b9ecac1293 --- /dev/null +++ b/examples/opengl/paintedwindow/paintedwindow.cpp @@ -0,0 +1,124 @@ +#include "paintedwindow.h" + +#include +#include +#include +#include + +#include + +PaintedWindow::PaintedWindow() + : m_fbo(0) +{ + QSurfaceFormat format; + format.setStencilBufferSize(8); + + setSurfaceType(QWindow::OpenGLSurface); + setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint); + setFormat(format); + + create(); + + m_context = new QOpenGLContext(this); + m_context->setFormat(format); + m_context->create(); + + QTimer *timer = new QTimer(this); + timer->setInterval(16); + connect(timer, SIGNAL(timeout()), this, SLOT(paint())); + timer->start(); + + m_context->makeCurrent(this); + + QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this); + const char *vsrc = + "attribute highp vec2 vertexCoordsInput;\n" + "attribute mediump vec2 texCoordsInput;\n" + "varying mediump vec2 texCoords;\n" + "void main(void)\n" + "{\n" + " texCoords = texCoordsInput;\n" + " gl_Position = vec4(vertexCoordsInput, 0, 1);\n" + "}\n"; + vshader->compileSourceCode(vsrc); + + QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this); + const char *fsrc = + "uniform sampler2D tex;\n" + "varying mediump vec2 texCoords;\n" + "void main(void)\n" + "{\n" + " gl_FragColor = texture2D(tex, texCoords);\n" + "}\n"; + fshader->compileSourceCode(fsrc); + + m_program = new QOpenGLShaderProgram; + m_program->addShader(vshader); + m_program->addShader(fshader); + m_program->link(); + + m_vertexAttribute = m_program->attributeLocation("vertexCoordsInput"); + m_texCoordsAttribute = m_program->attributeLocation("texCoordsInput"); +} + +void PaintedWindow::resizeEvent(QResizeEvent *) +{ + m_context->makeCurrent(this); + + delete m_fbo; + m_fbo = new QOpenGLFramebufferObject(size()); +} + +void PaintedWindow::paint() +{ + if (!m_fbo) + return; + + m_context->makeCurrent(this); + + QPainterPath path; + path.addEllipse(0, 0, m_fbo->width(), m_fbo->height()); + + QPainter painter; + painter.begin(m_fbo); + painter.fillRect(0, 0, m_fbo->width(), m_fbo->height(), Qt::white); + painter.setRenderHint(QPainter::Antialiasing); + painter.fillPath(path, Qt::blue); + painter.end(); + + glViewport(0, 0, width(), height()); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + glDisable(GL_BLEND); + + glClearColor(0.1f, 0.1f, 0.2f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + GLfloat texCoords[] = { 0, 0, 1, 0, 0, 1, + 1, 0, 1, 1, 0, 1 }; + + GLfloat vertexCoords[] = { -1, -1, 1, -1, -1, 1, + 1, -1, 1, 1, -1, 1 }; + + m_program->bind(); + + m_context->functions()->glEnableVertexAttribArray(m_vertexAttribute); + m_context->functions()->glEnableVertexAttribArray(m_texCoordsAttribute); + + m_context->functions()->glVertexAttribPointer(m_vertexAttribute, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords); + m_context->functions()->glVertexAttribPointer(m_texCoordsAttribute, 2, GL_FLOAT, GL_FALSE, 0, texCoords); + + glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); + + glDrawArrays(GL_TRIANGLES, 0, 6); + + glBindTexture(GL_TEXTURE_2D, 0); + + m_context->functions()->glDisableVertexAttribArray(m_vertexAttribute); + m_context->functions()->glDisableVertexAttribArray(m_texCoordsAttribute); + + m_program->release(); + + m_context->swapBuffers(this); +} diff --git a/examples/opengl/paintedwindow/paintedwindow.h b/examples/opengl/paintedwindow/paintedwindow.h new file mode 100644 index 0000000000..9e1b43638c --- /dev/null +++ b/examples/opengl/paintedwindow/paintedwindow.h @@ -0,0 +1,30 @@ +#include + +#include +#include +#include + +#include +#include + +class QOpenGLContext; + +class PaintedWindow : public QWindow +{ + Q_OBJECT +public: + PaintedWindow(); + +private slots: + void paint(); + +private: + void resizeEvent(QResizeEvent *); + + QOpenGLContext *m_context; + QOpenGLFramebufferObject *m_fbo; + QOpenGLShaderProgram *m_program; + + GLuint m_vertexAttribute; + GLuint m_texCoordsAttribute; +}; diff --git a/examples/opengl/paintedwindow/paintedwindow.pro b/examples/opengl/paintedwindow/paintedwindow.pro new file mode 100644 index 0000000000..a3ae3bace5 --- /dev/null +++ b/examples/opengl/paintedwindow/paintedwindow.pro @@ -0,0 +1,18 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Wed Apr 27 16:40:46 2011 +###################################################################### + +TEMPLATE = app +DEPENDPATH += . +INCLUDEPATH += . + +# Input +HEADERS += paintedwindow.h +SOURCES += paintedwindow.cpp main.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/qtbase/opengl/paintedwindow +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS paintedwindow.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qtbase/opengl/paintedwindow +INSTALLS += target sources + diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h index 9b0d82e69f..e0c02aa150 100644 --- a/src/gui/egl/qegl_p.h +++ b/src/gui/egl/qegl_p.h @@ -47,7 +47,7 @@ // ------------- // // This file is not part of the Qt API. It exists for the convenience of -// the QtOpenGL and QtOpenVG modules. This header file may change from +// the QtGui and QtOpenVG modules. This header file may change from // version to version without notice, or even be removed. // // We mean it. diff --git a/src/gui/egl/qegl_qpa.cpp b/src/gui/egl/qegl_qpa.cpp index 167a65bab5..c3eb044b22 100644 --- a/src/gui/egl/qegl_qpa.cpp +++ b/src/gui/egl/qegl_qpa.cpp @@ -94,7 +94,7 @@ void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) if (!dev) return; - // Find the QGLScreen for this paint device. + // Find the QOpenGLScreen for this paint device. QPlatformScreen *screen = screenForDevice(dev); if (!screen) return; diff --git a/src/gui/egl/qeglcontext_p.h b/src/gui/egl/qeglcontext_p.h index 16da430130..7ea18627d1 100644 --- a/src/gui/egl/qeglcontext_p.h +++ b/src/gui/egl/qeglcontext_p.h @@ -47,7 +47,7 @@ // ------------- // // This file is not part of the Qt API. It exists for the convenience of -// the QtOpenGL and QtOpenVG modules. This header file may change from +// the QtGui and QtOpenVG modules. This header file may change from // version to version without notice, or even be removed. // // We mean it. diff --git a/src/gui/egl/qeglproperties_p.h b/src/gui/egl/qeglproperties_p.h index 2d03cd0494..d8d64e01a1 100644 --- a/src/gui/egl/qeglproperties_p.h +++ b/src/gui/egl/qeglproperties_p.h @@ -47,7 +47,7 @@ // ------------- // // This file is not part of the Qt API. It exists for the convenience -// of the QtOpenGL and QtOpenVG modules. This header file may change from +// of the QtGui and QtOpenVG modules. This header file may change from // version to version without notice, or even be removed. // // We mean it. diff --git a/src/gui/gui.pro b/src/gui/gui.pro index f1d5bbaea5..4ee9d764ec 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -21,6 +21,7 @@ include(text/text.pri) include(painting/painting.pri) include(util/util.pri) include(math3d/math3d.pri) +include(opengl/opengl.pri) include(egl/egl.pri) diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index 402708b48c..330370e25b 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -182,7 +182,7 @@ private: friend class QBitmap; friend class QPaintDevice; friend class QPainter; - friend class QGLWidget; + friend class QOpenGLWidget; friend class QWidgetPrivate; friend class QRasterBuffer; #if !defined(QT_NO_DATASTREAM) diff --git a/src/gui/image/qplatformpixmap.cpp b/src/gui/image/qplatformpixmap.cpp index 7fb1bd6530..a214f397ed 100644 --- a/src/gui/image/qplatformpixmap.cpp +++ b/src/gui/image/qplatformpixmap.cpp @@ -73,7 +73,7 @@ QPlatformPixmap::QPlatformPixmap(PixelType pixelType, int objectId) QPlatformPixmap::~QPlatformPixmap() { // Sometimes the pixmap cleanup hooks will be called from derrived classes, which will - // then set is_cached to false. For example, on X11 QtOpenGL needs to delete the GLXPixmap + // then set is_cached to false. For example, on X11 QtGui needs to delete the GLXPixmap // or EGL Pixmap Surface for a given pixmap _before_ the native X11 pixmap is deleted, // otherwise some drivers will leak the GL surface. In this case, QX11PlatformPixmap will // call the cleanup hooks itself before deleting the native pixmap and set is_cached to diff --git a/src/gui/image/qplatformpixmap_qpa.h b/src/gui/image/qplatformpixmap_qpa.h index 5f5b903962..d528f4138f 100644 --- a/src/gui/image/qplatformpixmap_qpa.h +++ b/src/gui/image/qplatformpixmap_qpa.h @@ -136,7 +136,7 @@ protected: private: friend class QPixmap; friend class QImagePixmapCleanupHooks; // Needs to set is_cached - friend class QGLTextureCache; //Needs to check the reference count + friend class QOpenGLTextureCache; //Needs to check the reference count friend class QExplicitlySharedDataPointer; QAtomicInt ref; diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 44d039512f..b24d51c17d 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -49,9 +49,9 @@ qpa { kernel/qplatformintegrationfactory_qpa_p.h \ kernel/qplatformintegrationplugin_qpa.h \ kernel/qplatformwindow_qpa.h \ - kernel/qplatformglcontext_qpa.h \ - kernel/qguiglcontext_qpa.h \ - kernel/qguiglcontext_qpa_p.h \ + kernel/qplatformopenglcontext_qpa.h \ + kernel/qopenglcontext.h \ + kernel/qopenglcontext_p.h \ kernel/qplatformcursor_qpa.h \ kernel/qplatformclipboard_qpa.h \ kernel/qplatformnativeinterface_qpa.h \ @@ -73,8 +73,8 @@ qpa { kernel/qplatformintegrationfactory_qpa.cpp \ kernel/qplatformintegrationplugin_qpa.cpp \ kernel/qplatformwindow_qpa.cpp \ - kernel/qplatformglcontext_qpa.cpp \ - kernel/qguiglcontext_qpa.cpp \ + kernel/qplatformopenglcontext_qpa.cpp \ + kernel/qopenglcontext.cpp \ kernel/qplatformcursor_qpa.cpp \ kernel/qplatformclipboard_qpa.cpp \ kernel/qplatformnativeinterface_qpa.cpp \ diff --git a/src/gui/kernel/qguiglcontext_qpa_p.h b/src/gui/kernel/qguiglcontext_qpa_p.h deleted file mode 100644 index a9c8f5c75e..0000000000 --- a/src/gui/kernel/qguiglcontext_qpa_p.h +++ /dev/null @@ -1,181 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGUIGLCONTEXT_P_H -#define QGUIGLCONTEXT_P_H - -#include "qguiglcontext_qpa.h" -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) - -class QGuiGLContext; -class QGLMultiGroupSharedResource; - -class Q_GUI_EXPORT QGLSharedResource -{ -public: - QGLSharedResource(QGuiGLContextGroup *group); - virtual ~QGLSharedResource() = 0; - - QGuiGLContextGroup *group() const { return m_group; } - - // schedule the resource for deletion at an appropriate time - void free(); - -protected: - // the resource's share group no longer exists, invalidate the resource - virtual void invalidateResource() = 0; - - // a valid context in the group is current, free the resource - virtual void freeResource(QGuiGLContext *context) = 0; - -private: - QGuiGLContextGroup *m_group; - - friend class QGuiGLContextGroup; - friend class QGuiGLContextGroupPrivate; - - Q_DISABLE_COPY(QGLSharedResource); -}; - -class Q_GUI_EXPORT QGuiGLContextGroupPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QGuiGLContextGroup); -public: - QGuiGLContextGroupPrivate() - : m_context(0) - , m_mutex(QMutex::Recursive) - , m_refs(0) - { - } - - void addContext(QGuiGLContext *ctx); - void removeContext(QGuiGLContext *ctx); - - void deletePendingResources(QGuiGLContext *ctx); - - QGuiGLContext *m_context; - - QList m_shares; - QMutex m_mutex; - - QHash m_resources; - QAtomicInt m_refs; - - QList m_sharedResources; - QList m_pendingDeletion; - - void cleanupResources(QGuiGLContext *ctx); -}; - -class Q_GUI_EXPORT QGLMultiGroupSharedResource -{ -public: - QGLMultiGroupSharedResource(); - ~QGLMultiGroupSharedResource(); - - void insert(QGuiGLContext *context, QGLSharedResource *value); - void cleanup(QGuiGLContext *context); - void cleanup(QGuiGLContext *context, QGLSharedResource *value); - - QGLSharedResource *value(QGuiGLContext *context); - - template - T *value(QGuiGLContext *context) { - QGuiGLContextGroup *group = context->shareGroup(); - T *resource = static_cast(group->d_func()->m_resources.value(this, 0)); - if (!resource) { - resource = new T(context); - insert(context, resource); - } - return resource; - } - -private: - QAtomicInt active; - QList m_groups; -}; - -class Q_GUI_EXPORT QGuiGLContextPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QGuiGLContext); -public: - QGuiGLContextPrivate() - : qGLContextHandle(0) - , platformGLContext(0) - , shareContext(0) - , shareGroup(0) - , screen(0) - , surface(0) - { - } - - virtual ~QGuiGLContextPrivate() - { - //do not delete the QGLContext handle here as it is deleted in - //QWidgetPrivate::deleteTLSysExtra() - } - void *qGLContextHandle; - void (*qGLContextDeleteFunction)(void *handle); - - QSurfaceFormat requestedFormat; - QPlatformGLContext *platformGLContext; - QGuiGLContext *shareContext; - QGuiGLContextGroup *shareGroup; - QScreen *screen; - QSurface *surface; - - QHash m_resources; - - static void setCurrentContext(QGuiGLContext *context); -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QGUIGLCONTEXT_P_H diff --git a/src/gui/kernel/qguiglcontext_qpa.cpp b/src/gui/kernel/qopenglcontext.cpp similarity index 60% rename from src/gui/kernel/qguiglcontext_qpa.cpp rename to src/gui/kernel/qopenglcontext.cpp index 71c830174e..92a651ddf4 100644 --- a/src/gui/kernel/qguiglcontext_qpa.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtOpenGL module of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -39,9 +39,9 @@ ** ****************************************************************************/ -#include "qplatformglcontext_qpa.h" -#include "qguiglcontext_qpa.h" -#include "qguiglcontext_qpa_p.h" +#include "qplatformopenglcontext_qpa.h" +#include "qopenglcontext.h" +#include "qopenglcontext_p.h" #include "qwindow.h" #include @@ -50,6 +50,8 @@ #include #include +#include + #include class QGuiGLThreadContext @@ -59,12 +61,12 @@ public: if (context) context->doneCurrent(); } - QGuiGLContext *context; + QOpenGLContext *context; }; static QThreadStorage qwindow_context_storage; -void QGuiGLContextPrivate::setCurrentContext(QGuiGLContext *context) +void QOpenGLContextPrivate::setCurrentContext(QOpenGLContext *context) { QGuiGLThreadContext *threadContext = qwindow_context_storage.localData(); if (!threadContext) { @@ -81,7 +83,7 @@ void QGuiGLContextPrivate::setCurrentContext(QGuiGLContext *context) /*! Returns the last context which called makeCurrent. This function is thread aware. */ -QGuiGLContext* QGuiGLContext::currentContext() +QOpenGLContext* QOpenGLContext::currentContext() { QGuiGLThreadContext *threadContext = qwindow_context_storage.localData(); if(threadContext) { @@ -90,20 +92,20 @@ QGuiGLContext* QGuiGLContext::currentContext() return 0; } -bool QGuiGLContext::areSharing(QGuiGLContext *first, QGuiGLContext *second) +bool QOpenGLContext::areSharing(QOpenGLContext *first, QOpenGLContext *second) { return first->shareGroup() == second->shareGroup(); } -QPlatformGLContext *QGuiGLContext::handle() const +QPlatformOpenGLContext *QOpenGLContext::handle() const { - Q_D(const QGuiGLContext); + Q_D(const QOpenGLContext); return d->platformGLContext; } -QPlatformGLContext *QGuiGLContext::shareHandle() const +QPlatformOpenGLContext *QOpenGLContext::shareHandle() const { - Q_D(const QGuiGLContext); + Q_D(const QOpenGLContext); if (d->shareContext) return d->shareContext->handle(); return 0; @@ -112,37 +114,37 @@ QPlatformGLContext *QGuiGLContext::shareHandle() const /*! Creates a new GL context instance, you need to call create() before it can be used. */ -QGuiGLContext::QGuiGLContext() - : QObject(*new QGuiGLContextPrivate()) +QOpenGLContext::QOpenGLContext(QObject *parent) + : QObject(*new QOpenGLContextPrivate(), parent) { - Q_D(QGuiGLContext); + Q_D(QOpenGLContext); d->screen = QGuiApplication::primaryScreen(); } /*! Sets the format the GL context should be compatible with. You need to call create() before it takes effect. */ -void QGuiGLContext::setFormat(const QSurfaceFormat &format) +void QOpenGLContext::setFormat(const QSurfaceFormat &format) { - Q_D(QGuiGLContext); + Q_D(QOpenGLContext); d->requestedFormat = format; } /*! Sets the context to share textures, shaders, and other GL resources with. You need to call create() before it takes effect. */ -void QGuiGLContext::setShareContext(QGuiGLContext *shareContext) +void QOpenGLContext::setShareContext(QOpenGLContext *shareContext) { - Q_D(QGuiGLContext); + Q_D(QOpenGLContext); d->shareContext = shareContext; } /*! Sets the screen the GL context should be valid for. You need to call create() before it takes effect. */ -void QGuiGLContext::setScreen(QScreen *screen) +void QOpenGLContext::setScreen(QScreen *screen) { - Q_D(QGuiGLContext); + Q_D(QOpenGLContext); d->screen = screen; if (!d->screen) d->screen = QGuiApplication::primaryScreen(); @@ -153,34 +155,36 @@ void QGuiGLContext::setScreen(QScreen *screen) Returns true if the native context was successfully created and is ready to be used. */ -bool QGuiGLContext::create() +bool QOpenGLContext::create() { destroy(); - Q_D(QGuiGLContext); - d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformGLContext(this); + Q_D(QOpenGLContext); + d->platformGLContext = QGuiApplicationPrivate::platformIntegration()->createPlatformOpenGLContext(this); d->platformGLContext->setContext(this); - d->shareGroup = d->shareContext ? d->shareContext->shareGroup() : new QGuiGLContextGroup; + d->shareGroup = d->shareContext ? d->shareContext->shareGroup() : new QOpenGLContextGroup; d->shareGroup->d_func()->addContext(this); return d->platformGLContext; } -void QGuiGLContext::destroy() +void QOpenGLContext::destroy() { - Q_D(QGuiGLContext); - if (QGuiGLContext::currentContext() == this) + Q_D(QOpenGLContext); + if (QOpenGLContext::currentContext() == this) doneCurrent(); if (d->shareGroup) d->shareGroup->d_func()->removeContext(this); d->shareGroup = 0; delete d->platformGLContext; d->platformGLContext = 0; + delete d->functions; + d->functions = 0; } /*! If this is the current context for the thread, doneCurrent is called */ -QGuiGLContext::~QGuiGLContext() +QOpenGLContext::~QOpenGLContext() { destroy(); } @@ -188,18 +192,32 @@ QGuiGLContext::~QGuiGLContext() /*! Returns if this context is valid, i.e. has been successfully created. */ -bool QGuiGLContext::isValid() const +bool QOpenGLContext::isValid() const { - Q_D(const QGuiGLContext); + Q_D(const QOpenGLContext); return d->platformGLContext != 0; } +/*! + Get the QOpenGLFunctions instance for this context. + + The context or a sharing context must be current. +*/ + +QOpenGLFunctions *QOpenGLContext::functions() const +{ + Q_D(const QOpenGLContext); + if (!d->functions) + const_cast(d->functions) = new QOpenGLExtensions(QOpenGLContext::currentContext()); + return d->functions; +} + /*! If surface is 0 this is equivalent to calling doneCurrent(). */ -bool QGuiGLContext::makeCurrent(QSurface *surface) +bool QOpenGLContext::makeCurrent(QSurface *surface) { - Q_D(QGuiGLContext); + Q_D(QOpenGLContext); if (!d->platformGLContext) return false; @@ -212,7 +230,7 @@ bool QGuiGLContext::makeCurrent(QSurface *surface) return false; if (d->platformGLContext->makeCurrent(surface->surfaceHandle())) { - QGuiGLContextPrivate::setCurrentContext(this); + QOpenGLContextPrivate::setCurrentContext(this); d->surface = surface; d->shareGroup->d_func()->deletePendingResources(this); @@ -226,17 +244,17 @@ bool QGuiGLContext::makeCurrent(QSurface *surface) /*! Convenience function for calling makeCurrent with a 0 surface. */ -void QGuiGLContext::doneCurrent() +void QOpenGLContext::doneCurrent() { - Q_D(QGuiGLContext); + Q_D(QOpenGLContext); if (!d->platformGLContext) return; - if (QGuiGLContext::currentContext() == this) + if (QOpenGLContext::currentContext() == this) d->shareGroup->d_func()->deletePendingResources(this); d->platformGLContext->doneCurrent(); - QGuiGLContextPrivate::setCurrentContext(0); + QOpenGLContextPrivate::setCurrentContext(0); d->surface = 0; } @@ -244,58 +262,58 @@ void QGuiGLContext::doneCurrent() /*! Returns the surface the context is current for. */ -QSurface *QGuiGLContext::surface() const +QSurface *QOpenGLContext::surface() const { - Q_D(const QGuiGLContext); + Q_D(const QOpenGLContext); return d->surface; } -void QGuiGLContext::swapBuffers(QSurface *surface) +void QOpenGLContext::swapBuffers(QSurface *surface) { - Q_D(QGuiGLContext); + Q_D(QOpenGLContext); if (!d->platformGLContext) return; if (!surface) { - qWarning() << "QGuiGLContext::swapBuffers() called with null argument"; + qWarning() << "QOpenGLContext::swapBuffers() called with null argument"; return; } d->platformGLContext->swapBuffers(surface->surfaceHandle()); } -void (*QGuiGLContext::getProcAddress(const QByteArray &procName)) () +void (*QOpenGLContext::getProcAddress(const QByteArray &procName)) () { - Q_D(QGuiGLContext); + Q_D(QOpenGLContext); if (!d->platformGLContext) return 0; return d->platformGLContext->getProcAddress(procName); } -QSurfaceFormat QGuiGLContext::format() const +QSurfaceFormat QOpenGLContext::format() const { - Q_D(const QGuiGLContext); + Q_D(const QOpenGLContext); if (!d->platformGLContext) return d->requestedFormat; return d->platformGLContext->format(); } -QGuiGLContextGroup *QGuiGLContext::shareGroup() const +QOpenGLContextGroup *QOpenGLContext::shareGroup() const { - Q_D(const QGuiGLContext); + Q_D(const QOpenGLContext); return d->shareGroup; } -QGuiGLContext *QGuiGLContext::shareContext() const +QOpenGLContext *QOpenGLContext::shareContext() const { - Q_D(const QGuiGLContext); + Q_D(const QOpenGLContext); return d->shareContext; } -QScreen *QGuiGLContext::screen() const +QScreen *QOpenGLContext::screen() const { - Q_D(const QGuiGLContext); + Q_D(const QOpenGLContext); return d->screen; } @@ -303,22 +321,22 @@ QScreen *QGuiGLContext::screen() const internal: Needs to have a pointer to qGLContext. But since this is in QtGui we cant have any type information. */ -void *QGuiGLContext::qGLContextHandle() const +void *QOpenGLContext::qGLContextHandle() const { - Q_D(const QGuiGLContext); + Q_D(const QOpenGLContext); return d->qGLContextHandle; } -void QGuiGLContext::setQGLContextHandle(void *handle,void (*qGLContextDeleteFunction)(void *)) +void QOpenGLContext::setQGLContextHandle(void *handle,void (*qGLContextDeleteFunction)(void *)) { - Q_D(QGuiGLContext); + Q_D(QOpenGLContext); d->qGLContextHandle = handle; d->qGLContextDeleteFunction = qGLContextDeleteFunction; } -void QGuiGLContext::deleteQGLContext() +void QOpenGLContext::deleteQGLContext() { - Q_D(QGuiGLContext); + Q_D(QOpenGLContext); if (d->qGLContextDeleteFunction && d->qGLContextHandle) { d->qGLContextDeleteFunction(d->qGLContextHandle); d->qGLContextDeleteFunction = 0; @@ -326,17 +344,17 @@ void QGuiGLContext::deleteQGLContext() } } -QGuiGLContextGroup::QGuiGLContextGroup() - : QObject(*new QGuiGLContextGroupPrivate()) +QOpenGLContextGroup::QOpenGLContextGroup() + : QObject(*new QOpenGLContextGroupPrivate()) { } -QGuiGLContextGroup::~QGuiGLContextGroup() +QOpenGLContextGroup::~QOpenGLContextGroup() { - Q_D(QGuiGLContextGroup); + Q_D(QOpenGLContextGroup); - QList::iterator it = d->m_sharedResources.begin(); - QList::iterator end = d->m_sharedResources.end(); + QList::iterator it = d->m_sharedResources.begin(); + QList::iterator end = d->m_sharedResources.end(); while (it != end) { (*it)->invalidateResource(); @@ -347,28 +365,28 @@ QGuiGLContextGroup::~QGuiGLContextGroup() qDeleteAll(d->m_pendingDeletion.begin(), d->m_pendingDeletion.end()); } -QList QGuiGLContextGroup::shares() const +QList QOpenGLContextGroup::shares() const { - Q_D(const QGuiGLContextGroup); + Q_D(const QOpenGLContextGroup); return d->m_shares; } -QGuiGLContextGroup *QGuiGLContextGroup::currentContextGroup() +QOpenGLContextGroup *QOpenGLContextGroup::currentContextGroup() { - QGuiGLContext *current = QGuiGLContext::currentContext(); + QOpenGLContext *current = QOpenGLContext::currentContext(); return current ? current->shareGroup() : 0; } -void QGuiGLContextGroupPrivate::addContext(QGuiGLContext *ctx) +void QOpenGLContextGroupPrivate::addContext(QOpenGLContext *ctx) { QMutexLocker locker(&m_mutex); m_refs.ref(); m_shares << ctx; } -void QGuiGLContextGroupPrivate::removeContext(QGuiGLContext *ctx) +void QOpenGLContextGroupPrivate::removeContext(QOpenGLContext *ctx) { - Q_Q(QGuiGLContextGroup); + Q_Q(QOpenGLContextGroup); QMutexLocker locker(&m_mutex); m_shares.removeOne(ctx); @@ -380,33 +398,35 @@ void QGuiGLContextGroupPrivate::removeContext(QGuiGLContext *ctx) q->deleteLater(); } -void QGuiGLContextGroupPrivate::deletePendingResources(QGuiGLContext *ctx) +void QOpenGLContextGroupPrivate::deletePendingResources(QOpenGLContext *ctx) { QMutexLocker locker(&m_mutex); - QList::iterator it = m_pendingDeletion.begin(); - QList::iterator end = m_pendingDeletion.end(); + QList pending = m_pendingDeletion; + m_pendingDeletion.clear(); + + QList::iterator it = pending.begin(); + QList::iterator end = pending.end(); while (it != end) { (*it)->freeResource(ctx); delete *it; ++it; } - m_pendingDeletion.clear(); } -QGLSharedResource::QGLSharedResource(QGuiGLContextGroup *group) +QOpenGLSharedResource::QOpenGLSharedResource(QOpenGLContextGroup *group) : m_group(group) { QMutexLocker locker(&m_group->d_func()->m_mutex); m_group->d_func()->m_sharedResources << this; } -QGLSharedResource::~QGLSharedResource() +QOpenGLSharedResource::~QOpenGLSharedResource() { } // schedule the resource for deletion at an appropriate time -void QGLSharedResource::free() +void QOpenGLSharedResource::free() { if (!m_group) { delete this; @@ -418,13 +438,22 @@ void QGLSharedResource::free() m_group->d_func()->m_pendingDeletion << this; // can we delete right away? - QGuiGLContext *current = QGuiGLContext::currentContext(); + QOpenGLContext *current = QOpenGLContext::currentContext(); if (current && current->shareGroup() == m_group) { m_group->d_func()->deletePendingResources(current); } } -QGLMultiGroupSharedResource::QGLMultiGroupSharedResource() +void QOpenGLSharedResourceGuard::freeResource(QOpenGLContext *context) +{ + if (m_id) { + QOpenGLFunctions functions(context); + m_func(&functions, m_id); + m_id = 0; + } +} + +QOpenGLMultiGroupSharedResource::QOpenGLMultiGroupSharedResource() : active(0) { #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG @@ -432,61 +461,63 @@ QGLMultiGroupSharedResource::QGLMultiGroupSharedResource() #endif } -QGLMultiGroupSharedResource::~QGLMultiGroupSharedResource() +QOpenGLMultiGroupSharedResource::~QOpenGLMultiGroupSharedResource() { #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size()); #endif for (int i = 0; i < m_groups.size(); ++i) { - QGuiGLContext *context = m_groups.at(i)->shares().first(); - QGLSharedResource *resource = value(context); - if (resource) - resource->free(); + if (!m_groups.at(i)->shares().isEmpty()) { + QOpenGLContext *context = m_groups.at(i)->shares().first(); + QOpenGLSharedResource *resource = value(context); + if (resource) + resource->free(); + } m_groups.at(i)->d_func()->m_resources.remove(this); active.deref(); } #ifndef QT_NO_DEBUG if (active != 0) { - qWarning("QtOpenGL: Resources are still available at program shutdown.\n" - " This is possibly caused by a leaked QGLWidget, \n" - " QGLFramebufferObject or QGLPixelBuffer."); + qWarning("QtGui: Resources are still available at program shutdown.\n" + " This is possibly caused by a leaked QOpenGLWidget, \n" + " QOpenGLFramebufferObject or QOpenGLPixelBuffer."); } #endif } -void QGLMultiGroupSharedResource::insert(QGuiGLContext *context, QGLSharedResource *value) +void QOpenGLMultiGroupSharedResource::insert(QOpenGLContext *context, QOpenGLSharedResource *value) { #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this); #endif - QGuiGLContextGroup *group = context->shareGroup(); + QOpenGLContextGroup *group = context->shareGroup(); Q_ASSERT(!group->d_func()->m_resources.contains(this)); group->d_func()->m_resources.insert(this, value); m_groups.append(group); active.ref(); } -QGLSharedResource *QGLMultiGroupSharedResource::value(QGuiGLContext *context) +QOpenGLSharedResource *QOpenGLMultiGroupSharedResource::value(QOpenGLContext *context) { - QGuiGLContextGroup *group = context->shareGroup(); + QOpenGLContextGroup *group = context->shareGroup(); return group->d_func()->m_resources.value(this, 0); } -void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx) +void QOpenGLMultiGroupSharedResource::cleanup(QOpenGLContext *ctx) { - QGLSharedResource *resource = value(ctx); + QOpenGLSharedResource *resource = value(ctx); if (resource != 0) { resource->free(); - QGuiGLContextGroup *group = ctx->shareGroup(); + QOpenGLContextGroup *group = ctx->shareGroup(); group->d_func()->m_resources.remove(this); m_groups.removeOne(group); active.deref(); } } -void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx, QGLSharedResource *value) +void QOpenGLMultiGroupSharedResource::cleanup(QOpenGLContext *ctx, QOpenGLSharedResource *value) { #ifdef QT_GL_CONTEXT_RESOURCE_DEBUG qDebug("Cleaning up context group resource %p, for context %p in thread %p.", this, ctx, QThread::currentThread()); @@ -494,7 +525,7 @@ void QGLMultiGroupSharedResource::cleanup(QGuiGLContext *ctx, QGLSharedResource value->free(); active.deref(); - QGuiGLContextGroup *group = ctx->shareGroup(); + QOpenGLContextGroup *group = ctx->shareGroup(); m_groups.removeOne(group); } diff --git a/src/gui/kernel/qguiglcontext_qpa.h b/src/gui/kernel/qopenglcontext.h similarity index 60% rename from src/gui/kernel/qguiglcontext_qpa.h rename to src/gui/kernel/qopenglcontext.h index a234bd3cb6..cf334709ec 100644 --- a/src/gui/kernel/qguiglcontext_qpa.h +++ b/src/gui/kernel/qopenglcontext.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtOpenGL module of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -39,13 +39,13 @@ ** ****************************************************************************/ -#ifndef QGUIGLCONTEXT_H -#define QGUIGLCONTEXT_H +#ifndef QOPENGLCONTEXT_H +#define QOPENGLCONTEXT_H #include #include -#include +#include QT_BEGIN_HEADER @@ -53,49 +53,52 @@ QT_BEGIN_NAMESPACE QT_MODULE(Gui) -class QGuiGLContextPrivate; -class QGuiGLContextGroupPrivate; -class QPlatformGLContext; +class QOpenGLContextPrivate; +class QOpenGLContextGroupPrivate; +class QOpenGLFunctions; +class QPlatformOpenGLContext; + +class QScreen; class QSurface; -class Q_GUI_EXPORT QGuiGLContextGroup : public QObject +class Q_GUI_EXPORT QOpenGLContextGroup : public QObject { Q_OBJECT - Q_DECLARE_PRIVATE(QGuiGLContextGroup) + Q_DECLARE_PRIVATE(QOpenGLContextGroup) public: - ~QGuiGLContextGroup(); + ~QOpenGLContextGroup(); - QList shares() const; + QList shares() const; - static QGuiGLContextGroup *currentContextGroup(); + static QOpenGLContextGroup *currentContextGroup(); private: - QGuiGLContextGroup(); + QOpenGLContextGroup(); - friend class QGuiGLContext; - friend class QGLContextGroupResourceBase; - friend class QGLSharedResource; - friend class QGLMultiGroupSharedResource; + friend class QOpenGLContext; + friend class QOpenGLContextGroupResourceBase; + friend class QOpenGLSharedResource; + friend class QOpenGLMultiGroupSharedResource; }; -class Q_GUI_EXPORT QGuiGLContext : public QObject +class Q_GUI_EXPORT QOpenGLContext : public QObject { Q_OBJECT - Q_DECLARE_PRIVATE(QGuiGLContext); + Q_DECLARE_PRIVATE(QOpenGLContext); public: - QGuiGLContext(); - ~QGuiGLContext(); + QOpenGLContext(QObject *parent = 0); + ~QOpenGLContext(); void setFormat(const QSurfaceFormat &format); - void setShareContext(QGuiGLContext *shareContext); + void setShareContext(QOpenGLContext *shareContext); void setScreen(QScreen *screen); bool create(); bool isValid() const; QSurfaceFormat format() const; - QGuiGLContext *shareContext() const; - QGuiGLContextGroup *shareGroup() const; + QOpenGLContext *shareContext() const; + QOpenGLContextGroup *shareGroup() const; QScreen *screen() const; bool makeCurrent(QSurface *surface); @@ -106,16 +109,26 @@ public: QSurface *surface() const; - static QGuiGLContext *currentContext(); - static bool areSharing(QGuiGLContext *first, QGuiGLContext *second); + static QOpenGLContext *currentContext(); + static bool areSharing(QOpenGLContext *first, QOpenGLContext *second); - QPlatformGLContext *handle() const; - QPlatformGLContext *shareHandle() const; + QPlatformOpenGLContext *handle() const; + QPlatformOpenGLContext *shareHandle() const; + + QOpenGLFunctions *functions() const; private: - //hack to make it work with QGLContext::CurrentContext friend class QGLContext; - friend class QGLContextResourceBase; + friend class QOpenGLContextResourceBase; + friend class QOpenGLPaintDevice; + friend class QOpenGLGlyphTexture; + friend class QOpenGLTextureGlyphCache; + friend class QOpenGLEngineShaderManager; + friend class QOpenGLFramebufferObject; + friend class QOpenGLFramebufferObjectPrivate; + friend class QOpenGL2PaintEngineEx; + friend class QOpenGL2PaintEngineExPrivate; + friend class QSGDistanceFieldGlyphCache; friend class QWidgetPrivate; void *qGLContextHandle() const; diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h new file mode 100644 index 0000000000..61cfbf9563 --- /dev/null +++ b/src/gui/kernel/qopenglcontext_p.h @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGUIGLCONTEXT_P_H +#define QGUIGLCONTEXT_P_H + +#include "qopengl.h" +#include "qopenglcontext.h" +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QOpenGLFunctions; +class QOpenGLContext; +class QOpenGLMultiGroupSharedResource; + +class Q_GUI_EXPORT QOpenGLSharedResource +{ +public: + QOpenGLSharedResource(QOpenGLContextGroup *group); + virtual ~QOpenGLSharedResource() = 0; + + QOpenGLContextGroup *group() const { return m_group; } + + // schedule the resource for deletion at an appropriate time + void free(); + +protected: + // the resource's share group no longer exists, invalidate the resource + virtual void invalidateResource() = 0; + + // a valid context in the group is current, free the resource + virtual void freeResource(QOpenGLContext *context) = 0; + +private: + QOpenGLContextGroup *m_group; + + friend class QOpenGLContextGroup; + friend class QOpenGLContextGroupPrivate; + + Q_DISABLE_COPY(QOpenGLSharedResource); +}; + +class Q_GUI_EXPORT QOpenGLSharedResourceGuard : public QOpenGLSharedResource +{ +public: + typedef void (*FreeResourceFunc)(QOpenGLFunctions *functions, GLuint id); + QOpenGLSharedResourceGuard(QOpenGLContext *context, GLuint id, FreeResourceFunc func) + : QOpenGLSharedResource(context->shareGroup()) + , m_id(id) + , m_func(func) + { + } + + GLuint id() const { return m_id; } + +protected: + void invalidateResource() + { + m_id = 0; + } + + void freeResource(QOpenGLContext *context); + +private: + GLuint m_id; + FreeResourceFunc m_func; +}; + +class Q_GUI_EXPORT QOpenGLContextGroupPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QOpenGLContextGroup); +public: + QOpenGLContextGroupPrivate() + : m_context(0) + , m_mutex(QMutex::Recursive) + , m_refs(0) + { + } + + void addContext(QOpenGLContext *ctx); + void removeContext(QOpenGLContext *ctx); + + void deletePendingResources(QOpenGLContext *ctx); + + QOpenGLContext *m_context; + + QList m_shares; + QMutex m_mutex; + + QHash m_resources; + QAtomicInt m_refs; + + QList m_sharedResources; + QList m_pendingDeletion; + + void cleanupResources(QOpenGLContext *ctx); +}; + +class Q_GUI_EXPORT QOpenGLMultiGroupSharedResource +{ +public: + QOpenGLMultiGroupSharedResource(); + ~QOpenGLMultiGroupSharedResource(); + + void insert(QOpenGLContext *context, QOpenGLSharedResource *value); + void cleanup(QOpenGLContext *context); + void cleanup(QOpenGLContext *context, QOpenGLSharedResource *value); + + QOpenGLSharedResource *value(QOpenGLContext *context); + + template + T *value(QOpenGLContext *context) { + QOpenGLContextGroup *group = context->shareGroup(); + T *resource = static_cast(group->d_func()->m_resources.value(this, 0)); + if (!resource) { + resource = new T(context); + insert(context, resource); + } + return resource; + } + +private: + QAtomicInt active; + QList m_groups; +}; + +class QPaintEngineEx; +class QOpenGLFunctions; + +class Q_GUI_EXPORT QOpenGLContextPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QOpenGLContext); +public: + QOpenGLContextPrivate() + : qGLContextHandle(0) + , platformGLContext(0) + , shareContext(0) + , shareGroup(0) + , screen(0) + , surface(0) + , functions(0) + , current_fbo(0) + , default_fbo(0) + , workaround_brokenFBOReadBack(false) + , workaround_brokenTexSubImage(false) + , active_engine(0) + { + } + + virtual ~QOpenGLContextPrivate() + { + //do not delete the QOpenGLContext handle here as it is deleted in + //QWidgetPrivate::deleteTLSysExtra() + } + + void *qGLContextHandle; + void (*qGLContextDeleteFunction)(void *handle); + + QSurfaceFormat requestedFormat; + QPlatformOpenGLContext *platformGLContext; + QOpenGLContext *shareContext; + QOpenGLContextGroup *shareGroup; + QScreen *screen; + QSurface *surface; + QOpenGLFunctions *functions; + + GLuint current_fbo; + GLuint default_fbo; + + bool workaround_brokenFBOReadBack; + bool workaround_brokenTexSubImage; + + QPaintEngineEx *active_engine; + + QHash m_resources; + + static void setCurrentContext(QOpenGLContext *context); + + int maxTextureSize() const { return 1024; } +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGUIGLCONTEXT_P_H diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp index ccbf52bb1e..39341fa88f 100644 --- a/src/gui/kernel/qplatformintegration_qpa.cpp +++ b/src/gui/kernel/qplatformintegration_qpa.cpp @@ -192,10 +192,10 @@ QPlatformPixmap *QPlatformIntegration::createPlatformPixmap(QPlatformPixmap::Pix return new QRasterPlatformPixmap(type); } -QPlatformGLContext *QPlatformIntegration::createPlatformGLContext(QGuiGLContext *context) const +QPlatformOpenGLContext *QPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { Q_UNUSED(context); - qWarning("This plugin does not support createPlatformGLContext!"); + qWarning("This plugin does not support createPlatformOpenGLContext!"); return 0; } diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h index 97811d45b5..d26fcfabb4 100644 --- a/src/gui/kernel/qplatformintegration_qpa.h +++ b/src/gui/kernel/qplatformintegration_qpa.h @@ -59,7 +59,7 @@ class QPlatformFontDatabase; class QPlatformClipboard; class QPlatformNativeInterface; class QPlatformDrag; -class QPlatformGLContext; +class QPlatformOpenGLContext; class QGuiGLFormat; class QAbstractEventDispatcher; class QPlatformInputContext; @@ -80,7 +80,7 @@ public: virtual QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; virtual QPlatformWindow *createPlatformWindow(QWindow *window) const = 0; virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const = 0; - virtual QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const; + virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; // Event dispatcher: virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const = 0; diff --git a/src/gui/kernel/qplatformnativeinterface_qpa.cpp b/src/gui/kernel/qplatformnativeinterface_qpa.cpp index 18bef8a595..20d136e691 100644 --- a/src/gui/kernel/qplatformnativeinterface_qpa.cpp +++ b/src/gui/kernel/qplatformnativeinterface_qpa.cpp @@ -50,7 +50,7 @@ void *QPlatformNativeInterface::nativeResourceForWindow(const QByteArray &resour return 0; } -void *QPlatformNativeInterface::nativeResourceForContext(const QByteArray &resource, QGuiGLContext *context) +void *QPlatformNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { Q_UNUSED(resource); Q_UNUSED(context); diff --git a/src/gui/kernel/qplatformnativeinterface_qpa.h b/src/gui/kernel/qplatformnativeinterface_qpa.h index 136191e2aa..6ea8104fa3 100644 --- a/src/gui/kernel/qplatformnativeinterface_qpa.h +++ b/src/gui/kernel/qplatformnativeinterface_qpa.h @@ -50,14 +50,14 @@ QT_BEGIN_NAMESPACE QT_MODULE(Gui) -class QGuiGLContext; +class QOpenGLContext; class QWindow; class QBackingStore; class Q_GUI_EXPORT QPlatformNativeInterface { public: - virtual void *nativeResourceForContext(const QByteArray &resource, QGuiGLContext *context); + virtual void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context); virtual void *nativeResourceForWindow(const QByteArray &resource, QWindow *window); virtual void *nativeResourceForBackingStore(const QByteArray &resource, QBackingStore *backingStore); }; diff --git a/src/gui/kernel/qplatformglcontext_qpa.cpp b/src/gui/kernel/qplatformopenglcontext_qpa.cpp similarity index 63% rename from src/gui/kernel/qplatformglcontext_qpa.cpp rename to src/gui/kernel/qplatformopenglcontext_qpa.cpp index 5ce7db09e2..2957b4db4b 100644 --- a/src/gui/kernel/qplatformglcontext_qpa.cpp +++ b/src/gui/kernel/qplatformopenglcontext_qpa.cpp @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtOpenGL module of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -39,73 +39,73 @@ ** ****************************************************************************/ -#include "qplatformglcontext_qpa.h" +#include "qplatformopenglcontext_qpa.h" /*! - \class QPlatformGLContext + \class QPlatformOpenGLContext \since 4.8 \internal \preliminary \ingroup qpa - \brief The QPlatformGLContext class provides an abstraction for native GL contexts. + \brief The QPlatformOpenGLContext class provides an abstraction for native GL contexts. In QPA the way to support OpenGL or OpenVG or other technologies that requires a native GL - context is through the QPlatformGLContext wrapper. + context is through the QPlatformOpenGLContext wrapper. - There is no factory function for QPlatformGLContexts, but rather only one accessor function. - The only place to retrieve a QPlatformGLContext from is through a QPlatformWindow. + There is no factory function for QPlatformOpenGLContexts, but rather only one accessor function. + The only place to retrieve a QPlatformOpenGLContext from is through a QPlatformWindow. The context which is current for a specific thread can be collected by the currentContext() - function. This is how QPlatformGLContext also makes it possible to use the QtOpenGL module - withhout using QGLWidget. When using QGLContext::currentContext(), it will ask - QPlatformGLContext for the currentContext. Then a corresponding QGLContext will be returned, - which maps to the QPlatformGLContext. + function. This is how QPlatformOpenGLContext also makes it possible to use the QtGui module + withhout using QOpenGLWidget. When using QOpenGLContext::currentContext(), it will ask + QPlatformOpenGLContext for the currentContext. Then a corresponding QOpenGLContext will be returned, + which maps to the QPlatformOpenGLContext. */ -/*! \fn void QPlatformGLContext::swapBuffers() +/*! \fn void QPlatformOpenGLContext::swapBuffers() Reimplement in subclass to native swap buffers calls The implementation must support being called in a thread different than the gui-thread. */ -/*! \fn void *QPlatformGLContext::getProcAddress(const QString &procName) +/*! \fn void *QPlatformOpenGLContext::getProcAddress(const QString &procName) Reimplement in subclass to native getProcAddr calls. Note: its convenient to use qPrintable(const QString &str) to get the const char * pointer */ -/*! \fn QPlatformWindowFormat QPlatformGLContext::platformWindowFormat() const +/*! \fn QPlatformWindowFormat QPlatformOpenGLContext::platformWindowFormat() const QWidget has the function qplatformWindowFormat(). That function is for the application programmer to request the format of the window and the context that he wants. Reimplement this function in a subclass to indicate what format the glContext actually has. */ -struct QPlatformGLContextPrivate +struct QPlatformOpenGLContextPrivate { - QGuiGLContext *context; + QOpenGLContext *context; }; -QPlatformGLContext::QPlatformGLContext() - : d_ptr(new QPlatformGLContextPrivate) +QPlatformOpenGLContext::QPlatformOpenGLContext() + : d_ptr(new QPlatformOpenGLContextPrivate) { - Q_D(QPlatformGLContext); + Q_D(QPlatformOpenGLContext); d->context = 0; } -QPlatformGLContext::~QPlatformGLContext() +QPlatformOpenGLContext::~QPlatformOpenGLContext() { } -QGuiGLContext *QPlatformGLContext::context() const +QOpenGLContext *QPlatformOpenGLContext::context() const { - Q_D(const QPlatformGLContext); + Q_D(const QPlatformOpenGLContext); return d->context; } -void QPlatformGLContext::setContext(QGuiGLContext *context) +void QPlatformOpenGLContext::setContext(QOpenGLContext *context) { - Q_D(QPlatformGLContext); + Q_D(QPlatformOpenGLContext); d->context = context; } diff --git a/src/gui/kernel/qplatformglcontext_qpa.h b/src/gui/kernel/qplatformopenglcontext_qpa.h similarity index 84% rename from src/gui/kernel/qplatformglcontext_qpa.h rename to src/gui/kernel/qplatformopenglcontext_qpa.h index 30d7186bd1..902ccdec6d 100644 --- a/src/gui/kernel/qplatformglcontext_qpa.h +++ b/src/gui/kernel/qplatformopenglcontext_qpa.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtOpenGL module of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -67,14 +67,14 @@ private: friend class QPlatformWindow; }; -class QPlatformGLContextPrivate; +class QPlatformOpenGLContextPrivate; -class Q_GUI_EXPORT QPlatformGLContext +class Q_GUI_EXPORT QPlatformOpenGLContext { - Q_DECLARE_PRIVATE(QPlatformGLContext) + Q_DECLARE_PRIVATE(QPlatformOpenGLContext) public: - QPlatformGLContext(); - virtual ~QPlatformGLContext(); + QPlatformOpenGLContext(); + virtual ~QPlatformOpenGLContext(); virtual QSurfaceFormat format() const = 0; @@ -85,16 +85,16 @@ public: virtual void (*getProcAddress(const QByteArray &procName)) () = 0; - QGuiGLContext *context() const; + QOpenGLContext *context() const; private: - friend class QGuiGLContext; + friend class QOpenGLContext; - QScopedPointer d_ptr; + QScopedPointer d_ptr; - void setContext(QGuiGLContext *context); + void setContext(QOpenGLContext *context); - Q_DISABLE_COPY(QPlatformGLContext) + Q_DISABLE_COPY(QPlatformOpenGLContext) }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformscreen_qpa.h b/src/gui/kernel/qplatformscreen_qpa.h index 8d3dd4cc71..3851b1821a 100644 --- a/src/gui/kernel/qplatformscreen_qpa.h +++ b/src/gui/kernel/qplatformscreen_qpa.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Gui) class QPlatformBackingStore; -class QPlatformGLContext; +class QPlatformOpenGLContext; class QPlatformScreenPrivate; class QPlatformWindow; class QScreen; diff --git a/src/gui/kernel/qplatformwindow_qpa.cpp b/src/gui/kernel/qplatformwindow_qpa.cpp index 766967eafa..0734fb7a26 100644 --- a/src/gui/kernel/qplatformwindow_qpa.cpp +++ b/src/gui/kernel/qplatformwindow_qpa.cpp @@ -260,7 +260,7 @@ bool QPlatformWindow::setMouseGrabEnabled(bool grab) However, it is not concerned with how Qt renders into the window it represents. Visible QWindows will always have a QPlatformWindow. However, it is not necessary for - all windows to have a QWindowSurface. This is the case for QGLWidget. And could be the case for + all windows to have a QWindowSurface. This is the case for QOpenGLWidget. And could be the case for windows where some 3.party renders into it. The platform specific window handle can be retrieved by the winId function. @@ -268,7 +268,7 @@ bool QPlatformWindow::setMouseGrabEnabled(bool grab) QPlatformWindow is also the way QPA defines how native child windows should be supported through the setParent function. - The only way to retrieve a QPlatformGLContext in QPA is by calling the glContext() function + The only way to retrieve a QPlatformOpenGLContext in QPA is by calling the glContext() function on QPlatformWindow. \sa QWindowSurface, QWindow diff --git a/src/gui/kernel/qplatformwindow_qpa.h b/src/gui/kernel/qplatformwindow_qpa.h index 680b24ac9b..ef2e07d774 100644 --- a/src/gui/kernel/qplatformwindow_qpa.h +++ b/src/gui/kernel/qplatformwindow_qpa.h @@ -47,7 +47,7 @@ #include #include #include -#include +#include QT_BEGIN_HEADER diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp index 063e68d29f..c53c510d8c 100644 --- a/src/gui/kernel/qsurfaceformat.cpp +++ b/src/gui/kernel/qsurfaceformat.cpp @@ -44,6 +44,14 @@ #include #include +#ifdef major +#undef major +#endif + +#ifdef minor +#undef minor +#endif + class QSurfaceFormatPrivate { public: @@ -59,6 +67,8 @@ public: , swapBehavior(QSurfaceFormat::DefaultSwapBehavior) , numSamples(-1) , profile(QSurfaceFormat::NoProfile) + , major(1) + , minor(1) { } @@ -73,7 +83,9 @@ public: stencilSize(other->stencilSize), swapBehavior(other->swapBehavior), numSamples(other->numSamples), - profile(other->profile) + profile(other->profile), + major(other->major), + minor(other->minor) { } @@ -88,6 +100,8 @@ public: QSurfaceFormat::SwapBehavior swapBehavior; int numSamples; QSurfaceFormat::OpenGLContextProfile profile; + int major; + int minor; }; QSurfaceFormat::QSurfaceFormat() : d(new QSurfaceFormatPrivate) @@ -351,6 +365,12 @@ void QSurfaceFormat::setAlphaBufferSize(int size) } } +/*! + Sets the desired OpenGL context profile. + + This setting is ignored if the requested OpenGL version is + less than 3.2. +*/ void QSurfaceFormat::setProfile(OpenGLContextProfile profile) { if (d->profile != profile) { @@ -364,6 +384,38 @@ QSurfaceFormat::OpenGLContextProfile QSurfaceFormat::profile() const return d->profile; } +/*! + Sets the desired major OpenGL version. +*/ +void QSurfaceFormat::setMajorVersion(int major) +{ + d->major = major; +} + +/*! + Returns the major OpenGL version. +*/ +int QSurfaceFormat::majorVersion() const +{ + return d->major; +} + +/*! + Sets the desired minor OpenGL version. +*/ +void QSurfaceFormat::setMinorVersion(int minor) +{ + d->minor = minor; +} + +/*! + Returns the minor OpenGL version. +*/ +int QSurfaceFormat::minorVersion() const +{ + return d->minor; +} + bool operator==(const QSurfaceFormat& a, const QSurfaceFormat& b) { return (a.d == b.d) || ((int) a.d->opts == (int) b.d->opts diff --git a/src/gui/kernel/qsurfaceformat.h b/src/gui/kernel/qsurfaceformat.h index 6e89aa667b..f305edbcc9 100644 --- a/src/gui/kernel/qsurfaceformat.h +++ b/src/gui/kernel/qsurfaceformat.h @@ -49,14 +49,16 @@ QT_BEGIN_NAMESPACE QT_MODULE(Gui) -class QGuiGLContext; +class QOpenGLContext; class QSurfaceFormatPrivate; class Q_GUI_EXPORT QSurfaceFormat { public: enum FormatOption { - StereoBuffers = 0x0001 + StereoBuffers = 0x0001, + DebugContext = 0x0002, + DeprecatedFunctions = 0x0004 }; Q_DECLARE_FLAGS(FormatOptions, FormatOption) @@ -105,6 +107,12 @@ public: void setProfile(OpenGLContextProfile profile); OpenGLContextProfile profile() const; + void setMajorVersion(int majorVersion); + int majorVersion() const; + + void setMinorVersion(int minorVersion); + int minorVersion() const; + bool stereo() const; void setStereo(bool enable); diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 6fbc249631..c6e479358d 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -43,8 +43,8 @@ #include "qplatformwindow_qpa.h" #include "qsurfaceformat.h" -#include "qplatformglcontext_qpa.h" -#include "qguiglcontext_qpa.h" +#include "qplatformopenglcontext_qpa.h" +#include "qopenglcontext.h" #include "qscreen.h" #include "qwindow_p.h" diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri new file mode 100644 index 0000000000..0401769ceb --- /dev/null +++ b/src/gui/opengl/opengl.pri @@ -0,0 +1,44 @@ +# Qt gui library, opengl module + +contains(QT_CONFIG, opengl):CONFIG += opengl +contains(QT_CONFIG, opengles2):CONFIG += opengles2 +contains(QT_CONFIG, egl):CONFIG += egl + +HEADERS += opengl/qopengl.h \ + opengl/qopengl_p.h \ + opengl/qopenglfunctions.h \ + opengl/qopenglframebufferobject.h \ + opengl/qopenglframebufferobject_p.h \ + opengl/qopenglpaintdevice_p.h \ + opengl/qopenglbuffer.h \ + opengl/qopenglshaderprogram.h \ + opengl/qopenglextensions_p.h \ + opengl/qopenglgradientcache_p.h \ + opengl/qopenglengineshadermanager_p.h \ + opengl/qopengl2pexvertexarray_p.h \ + opengl/qpaintengineex_opengl2_p.h \ + opengl/qopenglengineshadersource_p.h \ + opengl/qopenglcustomshaderstage_p.h \ + opengl/qtriangulatingstroker_p.h \ + opengl/qtriangulator_p.h \ + opengl/qrbtree_p.h \ + opengl/qtextureglyphcache_gl_p.h \ + opengl/qopenglshadercache_p.h \ + opengl/qopenglshadercache_meego_p.h + +SOURCES += opengl/qopengl.cpp \ + opengl/qopenglfunctions.cpp \ + opengl/qopenglframebufferobject.cpp \ + opengl/qopenglpaintdevice.cpp \ + opengl/qopenglbuffer.cpp \ + opengl/qopenglshaderprogram.cpp \ + opengl/qopenglgradientcache.cpp \ + opengl/qopenglengineshadermanager.cpp \ + opengl/qopengl2pexvertexarray.cpp \ + opengl/qpaintengineex_opengl2.cpp \ + opengl/qopenglcustomshaderstage.cpp \ + opengl/qtriangulatingstroker.cpp \ + opengl/qtriangulator.cpp \ + opengl/qtextureglyphcache_gl.cpp + +#INCLUDEPATH += ../3rdparty/harfbuzz/src diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp new file mode 100644 index 0000000000..3233fcfa5b --- /dev/null +++ b/src/gui/opengl/qopengl.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopengl_p.h" + +#include "qopenglcontext.h" + +QT_BEGIN_NAMESPACE + +QOpenGLExtensionMatcher::QOpenGLExtensionMatcher(const char *str) +{ + init(str); +} + +typedef GLubyte * (*qt_glGetStringi)(GLenum, GLuint); + +#ifndef GL_NUM_EXTENSIONS +#define GL_NUM_EXTENSIONS 0x821D +#endif + +QOpenGLExtensionMatcher::QOpenGLExtensionMatcher() +{ + const char *extensionStr = reinterpret_cast(glGetString(GL_EXTENSIONS)); + + if (extensionStr) { + init(extensionStr); + } else { + // clear error state + while (glGetError()) {} + + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (ctx) { + qt_glGetStringi glGetStringi = (qt_glGetStringi)ctx->getProcAddress("glGetStringi"); + + if (!glGetStringi) + return; + + GLint numExtensions; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions); + + for (int i = 0; i < numExtensions; ++i) { + const char *str = reinterpret_cast(glGetStringi(GL_EXTENSIONS, i)); + + m_offsets << m_extensions.size(); + + while (*str != 0) + m_extensions.append(*str++); + m_extensions.append(' '); + } + } + } +} + +void QOpenGLExtensionMatcher::init(const char *str) +{ + m_extensions = str; + + // make sure extension string ends with a space + if (!m_extensions.endsWith(' ')) + m_extensions.append(' '); + + int index = 0; + int next = 0; + while ((next = m_extensions.indexOf(' ', index)) >= 0) { + m_offsets << index; + index = next + 1; + } +} + + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengl.h b/src/gui/opengl/qopengl.h new file mode 100644 index 0000000000..7d75794956 --- /dev/null +++ b/src/gui/opengl/qopengl.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGL_H +#define QOPENGL_H + +#include + +QT_BEGIN_HEADER + +#if 1 +#if defined(QT_OPENGL_ES_2) +# if defined(Q_OS_MAC) +# include +# else +# include +# endif +# ifndef GL_DOUBLE +# define GL_DOUBLE GL_FLOAT +# endif +# ifndef GLdouble +typedef GLfloat GLdouble; +# endif +#else +# if defined(Q_OS_MAC) +# include +# else +# include +# endif +#endif +#endif + +QT_END_HEADER + +#endif // QOPENGL_H diff --git a/src/gui/opengl/qopengl2pexvertexarray.cpp b/src/gui/opengl/qopengl2pexvertexarray.cpp new file mode 100644 index 0000000000..ec26fdbf5b --- /dev/null +++ b/src/gui/opengl/qopengl2pexvertexarray.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopengl2pexvertexarray_p.h" + +#include + +QT_BEGIN_NAMESPACE + +void QOpenGL2PEXVertexArray::clear() +{ + vertexArray.reset(); + vertexArrayStops.reset(); + boundingRectDirty = true; +} + + +QOpenGLRect QOpenGL2PEXVertexArray::boundingRect() const +{ + if (boundingRectDirty) + return QOpenGLRect(0.0, 0.0, 0.0, 0.0); + else + return QOpenGLRect(minX, minY, maxX, maxY); +} + +void QOpenGL2PEXVertexArray::addClosingLine(int index) +{ + QPointF point(vertexArray.at(index)); + if (point != QPointF(vertexArray.last())) + vertexArray.add(point); +} + +void QOpenGL2PEXVertexArray::addCentroid(const QVectorPath &path, int subPathIndex) +{ + const QPointF *const points = reinterpret_cast(path.points()); + const QPainterPath::ElementType *const elements = path.elements(); + + QPointF sum = points[subPathIndex]; + int count = 1; + + for (int i = subPathIndex + 1; i < path.elementCount() && (!elements || elements[i] != QPainterPath::MoveToElement); ++i) { + sum += points[i]; + ++count; + } + + const QPointF centroid = sum / qreal(count); + vertexArray.add(centroid); +} + +void QOpenGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline) +{ + const QPointF* const points = reinterpret_cast(path.points()); + const QPainterPath::ElementType* const elements = path.elements(); + + if (boundingRectDirty) { + minX = maxX = points[0].x(); + minY = maxY = points[0].y(); + boundingRectDirty = false; + } + + if (!outline && !path.isConvex()) + addCentroid(path, 0); + + int lastMoveTo = vertexArray.size(); + vertexArray.add(points[0]); // The first element is always a moveTo + + do { + if (!elements) { +// qDebug("QVectorPath has no elements"); + // If the path has a null elements pointer, the elements implicitly + // start with a moveTo (already added) and continue with lineTos: + for (int i=1; i(64, qMax(bounds.width(), bounds.height()) * 3.14f / (curveInverseScale * 6)); + if (threshold < 3) threshold = 3; + qreal one_over_threshold_minus_1 = qreal(1) / (threshold - 1); + for (int t=0; t maxX) + maxX = x; + else if (x < minX) + minX = x; + if (y > maxY) + maxY = y; + else if (y < minY) + minY = y; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengl2pexvertexarray_p.h b/src/gui/opengl/qopengl2pexvertexarray_p.h new file mode 100644 index 0000000000..5ad4f7a237 --- /dev/null +++ b/src/gui/opengl/qopengl2pexvertexarray_p.h @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QOPENGL2PEXVERTEXARRAY_P_H +#define QOPENGL2PEXVERTEXARRAY_P_H + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QOpenGLPoint +{ +public: + QOpenGLPoint(GLfloat new_x, GLfloat new_y) : + x(new_x), y(new_y) {}; + + QOpenGLPoint(const QPointF &p) : + x(p.x()), y(p.y()) {}; + + QOpenGLPoint(const QPointF* p) : + x(p->x()), y(p->y()) {}; + + GLfloat x; + GLfloat y; + + operator QPointF() {return QPointF(x,y);} + operator QPointF() const {return QPointF(x,y);} +}; + +struct QOpenGLRect +{ + QOpenGLRect(const QRectF &r) + : left(r.left()), top(r.top()), right(r.right()), bottom(r.bottom()) {} + + QOpenGLRect(GLfloat l, GLfloat t, GLfloat r, GLfloat b) + : left(l), top(t), right(r), bottom(b) {} + + GLfloat left; + GLfloat top; + GLfloat right; + GLfloat bottom; + + operator QRectF() const {return QRectF(left, top, right-left, bottom-top);} +}; + +class QOpenGL2PEXVertexArray +{ +public: + QOpenGL2PEXVertexArray() : + vertexArray(0), vertexArrayStops(0), + maxX(-2e10), maxY(-2e10), minX(2e10), minY(2e10), + boundingRectDirty(true) + { } + + inline void addRect(const QRectF &rect) + { + qreal top = rect.top(); + qreal left = rect.left(); + qreal bottom = rect.bottom(); + qreal right = rect.right(); + + vertexArray << QOpenGLPoint(left, top) + << QOpenGLPoint(right, top) + << QOpenGLPoint(right, bottom) + << QOpenGLPoint(right, bottom) + << QOpenGLPoint(left, bottom) + << QOpenGLPoint(left, top); + } + + inline void addQuad(const QRectF &rect) + { + qreal top = rect.top(); + qreal left = rect.left(); + qreal bottom = rect.bottom(); + qreal right = rect.right(); + + vertexArray << QOpenGLPoint(left, top) + << QOpenGLPoint(right, top) + << QOpenGLPoint(left, bottom) + << QOpenGLPoint(right, bottom); + + } + + inline void addVertex(const GLfloat x, const GLfloat y) + { + vertexArray.add(QOpenGLPoint(x, y)); + } + + void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true); + void clear(); + + QOpenGLPoint* data() {return vertexArray.data();} + int *stops() const { return vertexArrayStops.data(); } + int stopCount() const { return vertexArrayStops.size(); } + QOpenGLRect boundingRect() const; + + int vertexCount() const { return vertexArray.size(); } + + void lineToArray(const GLfloat x, const GLfloat y); + +private: + QDataBuffer vertexArray; + QDataBuffer vertexArrayStops; + + GLfloat maxX; + GLfloat maxY; + GLfloat minX; + GLfloat minY; + bool boundingRectDirty; + void addClosingLine(int index); + void addCentroid(const QVectorPath &path, int subPathIndex); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/opengl/qopengl_p.h b/src/gui/opengl/qopengl_p.h new file mode 100644 index 0000000000..309ea22acd --- /dev/null +++ b/src/gui/opengl/qopengl_p.h @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGL_P_H +#define QOPENGL_P_H + +#include +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QOpenGLExtensionMatcher +{ +public: + QOpenGLExtensionMatcher(const char *str); + QOpenGLExtensionMatcher(); + + bool match(const char *str) const { + int str_length = qstrlen(str); + + Q_ASSERT(str); + Q_ASSERT(str_length > 0); + Q_ASSERT(str[str_length-1] != ' '); + + for (int i = 0; i < m_offsets.size(); ++i) { + const char *extension = m_extensions.constData() + m_offsets.at(i); + if (qstrncmp(extension, str, str_length) == 0 && extension[str_length] == ' ') + return true; + } + return false; + } + +private: + void init(const char *str); + + QByteArray m_extensions; + QVector m_offsets; +}; + +// this is a class that wraps a QThreadStorage object for storing +// thread local instances of the GL 1 and GL 2 paint engines + +class QPaintEngine; + +template +class QOpenGLEngineThreadStorage +{ +public: + QPaintEngine *engine() { + QPaintEngine *&localEngine = storage.localData(); + if (!localEngine) + localEngine = new T; + return localEngine; + } + +private: + QThreadStorage storage; +}; + +class QOpenGLTexture : public QOpenGLSharedResource { +public: + QOpenGLTexture(QOpenGLContext *ctx, GLuint id, bool inverted) + : QOpenGLSharedResource(ctx->shareGroup()) + , m_id(id) + , m_inverted(inverted) + { + } + + GLuint id() const { return m_id; } + bool invertedY() const { return m_inverted; } + +protected: + void invalidateResource() + { + m_id = 0; + } + + void freeResource(QOpenGLContext *) + { + glDeleteTextures(1, &m_id); + } + +private: + GLuint m_id; + bool m_inverted; +}; + +struct QOpenGLTextureCacheKey { + qint64 key; + QOpenGLContextGroup *group; +}; + +inline bool operator==(const QOpenGLTextureCacheKey &a, const QOpenGLTextureCacheKey &b) +{ + return a.key == b.key && a.group == b.group; +} + +inline uint qHash(const QOpenGLTextureCacheKey &key) +{ + return qHash(key.key) ^ qHash(key.group); +} + +class QPlatformPixmap; + +class QOpenGLTextureCache { +public: + QOpenGLTextureCache(); + ~QOpenGLTextureCache(); + + void insert(QOpenGLContext *ctx, qint64 key, QOpenGLTexture *texture, int cost); + void remove(qint64 key); + inline int size(); + inline void setMaxCost(int newMax); + inline int maxCost(); + inline QOpenGLTexture* getTexture(QOpenGLContext *ctx, qint64 key); + + bool remove(QOpenGLContext *ctx, GLuint textureId); + void removeContextTextures(QOpenGLContext *ctx); + static QOpenGLTextureCache *instance(); + static void cleanupTexturesForCacheKey(qint64 cacheKey); + static void cleanupTexturesForPixampData(QPlatformPixmap* pixmap); + static void cleanupBeforePixmapDestruction(QPlatformPixmap* pixmap); + +private: + QCache m_cache; + QReadWriteLock m_lock; +}; + +int QOpenGLTextureCache::size() { + QReadLocker locker(&m_lock); + return m_cache.size(); +} + +void QOpenGLTextureCache::setMaxCost(int newMax) +{ + QWriteLocker locker(&m_lock); + m_cache.setMaxCost(newMax); +} + +int QOpenGLTextureCache::maxCost() +{ + QReadLocker locker(&m_lock); + return m_cache.maxCost(); +} + +QOpenGLTexture* QOpenGLTextureCache::getTexture(QOpenGLContext *ctx, qint64 key) +{ + QReadLocker locker(&m_lock); + const QOpenGLTextureCacheKey cacheKey = { key, ctx->shareGroup() }; + return m_cache.object(cacheKey); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QOPENGL_H diff --git a/src/gui/opengl/qopenglbuffer.cpp b/src/gui/opengl/qopenglbuffer.cpp new file mode 100644 index 0000000000..612938df16 --- /dev/null +++ b/src/gui/opengl/qopenglbuffer.cpp @@ -0,0 +1,582 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include "qopenglbuffer.h" +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QOpenGLBuffer + \brief The QOpenGLBuffer class provides functions for creating and managing GL buffer objects. + \since 4.7 + \ingroup painting-3D + + Buffer objects are created in the GL server so that the + client application can avoid uploading vertices, indices, + texture image data, etc every time they are needed. + + QOpenGLBuffer objects can be copied around as a reference to the + underlying GL buffer object: + + \code + QOpenGLBuffer buffer1(QOpenGLBuffer::IndexBuffer); + buffer1.create(); + + QOpenGLBuffer buffer2 = buffer1; + \endcode + + QOpenGLBuffer performs a shallow copy when objects are copied in this + manner, but does not implement copy-on-write semantics. The original + object will be affected whenever the copy is modified. +*/ + +/*! + \enum QOpenGLBuffer::Type + This enum defines the type of GL buffer object to create with QOpenGLBuffer. + + \value VertexBuffer Vertex buffer object for use when specifying + vertex arrays. + \value IndexBuffer Index buffer object for use with \c{glDrawElements()}. + \value PixelPackBuffer Pixel pack buffer object for reading pixel + data from the GL server (for example, with \c{glReadPixels()}). + Not supported under OpenGL/ES. + \value PixelUnpackBuffer Pixel unpack buffer object for writing pixel + data to the GL server (for example, with \c{glTexImage2D()}). + Not supported under OpenGL/ES. +*/ + +/*! + \enum QOpenGLBuffer::UsagePattern + This enum defines the usage pattern of a QOpenGLBuffer object. + + \value StreamDraw The data will be set once and used a few times + for drawing operations. Under OpenGL/ES 1.1 this is identical + to StaticDraw. + \value StreamRead The data will be set once and used a few times + for reading data back from the GL server. Not supported + under OpenGL/ES. + \value StreamCopy The data will be set once and used a few times + for reading data back from the GL server for use in further + drawing operations. Not supported under OpenGL/ES. + \value StaticDraw The data will be set once and used many times + for drawing operations. + \value StaticRead The data will be set once and used many times + for reading data back from the GL server. Not supported + under OpenGL/ES. + \value StaticCopy The data will be set once and used many times + for reading data back from the GL server for use in further + drawing operations. Not supported under OpenGL/ES. + \value DynamicDraw The data will be modified repeatedly and used + many times for drawing operations. + \value DynamicRead The data will be modified repeatedly and used + many times for reading data back from the GL server. + Not supported under OpenGL/ES. + \value DynamicCopy The data will be modified repeatedly and used + many times for reading data back from the GL server for + use in further drawing operations. Not supported under OpenGL/ES. +*/ + +/*! + \enum QOpenGLBuffer::Access + This enum defines the access mode for QOpenGLBuffer::map(). + + \value ReadOnly The buffer will be mapped for reading only. + \value WriteOnly The buffer will be mapped for writing only. + \value ReadWrite The buffer will be mapped for reading and writing. +*/ + +class QOpenGLBufferPrivate +{ +public: + QOpenGLBufferPrivate(QOpenGLBuffer::Type t) + : ref(1), + type(t), + guard(0), + usagePattern(QOpenGLBuffer::StaticDraw), + actualUsagePattern(QOpenGLBuffer::StaticDraw), + funcs(0) + { + } + + QAtomicInt ref; + QOpenGLBuffer::Type type; + QOpenGLSharedResourceGuard *guard; + QOpenGLBuffer::UsagePattern usagePattern; + QOpenGLBuffer::UsagePattern actualUsagePattern; + QOpenGLExtensions *funcs; +}; + +/*! + Constructs a new buffer object of type QOpenGLBuffer::VertexBuffer. + + Note: this constructor just creates the QOpenGLBuffer instance. The actual + buffer object in the GL server is not created until create() is called. + + \sa create() +*/ +QOpenGLBuffer::QOpenGLBuffer() + : d_ptr(new QOpenGLBufferPrivate(QOpenGLBuffer::VertexBuffer)) +{ +} + +/*! + Constructs a new buffer object of \a type. + + Note: this constructor just creates the QOpenGLBuffer instance. The actual + buffer object in the GL server is not created until create() is called. + + \sa create() +*/ +QOpenGLBuffer::QOpenGLBuffer(QOpenGLBuffer::Type type) + : d_ptr(new QOpenGLBufferPrivate(type)) +{ +} + +/*! + Constructs a shallow copy of \a other. + + Note: QOpenGLBuffer does not implement copy-on-write semantics, + so \a other will be affected whenever the copy is modified. +*/ +QOpenGLBuffer::QOpenGLBuffer(const QOpenGLBuffer &other) + : d_ptr(other.d_ptr) +{ + d_ptr->ref.ref(); +} + +#define ctx QOpenGLContext::currentContext(); + +/*! + Destroys this buffer object, including the storage being + used in the GL server. +*/ +QOpenGLBuffer::~QOpenGLBuffer() +{ + if (!d_ptr->ref.deref()) { + destroy(); + delete d_ptr; + } +} + +/*! + Assigns a shallow copy of \a other to this object. + + Note: QOpenGLBuffer does not implement copy-on-write semantics, + so \a other will be affected whenever the copy is modified. +*/ +QOpenGLBuffer &QOpenGLBuffer::operator=(const QOpenGLBuffer &other) +{ + if (d_ptr != other.d_ptr) { + other.d_ptr->ref.ref(); + if (!d_ptr->ref.deref()) + destroy(); + d_ptr = other.d_ptr; + } + return *this; +} + +/*! + Returns the type of buffer represented by this object. +*/ +QOpenGLBuffer::Type QOpenGLBuffer::type() const +{ + Q_D(const QOpenGLBuffer); + return d->type; +} + +/*! + Returns the usage pattern for this buffer object. + The default value is StaticDraw. + + \sa setUsagePattern() +*/ +QOpenGLBuffer::UsagePattern QOpenGLBuffer::usagePattern() const +{ + Q_D(const QOpenGLBuffer); + return d->usagePattern; +} + +/*! + Sets the usage pattern for this buffer object to \a value. + This function must be called before allocate() or write(). + + \sa usagePattern(), allocate(), write() +*/ +void QOpenGLBuffer::setUsagePattern(QOpenGLBuffer::UsagePattern value) +{ + Q_D(QOpenGLBuffer); + d->usagePattern = d->actualUsagePattern = value; +} + +#undef ctx + +namespace { + void freeBufferFunc(QOpenGLFunctions *funcs, GLuint id) + { + funcs->glDeleteBuffers(1, &id); + } +} + +/*! + Creates the buffer object in the GL server. Returns true if + the object was created; false otherwise. + + This function must be called with a current QOpenGLContext. + The buffer will be bound to and can only be used in + that context (or any other context that is shared with it). + + This function will return false if the GL implementation + does not support buffers, or there is no current QOpenGLContext. + + \sa isCreated(), allocate(), write(), destroy() +*/ +bool QOpenGLBuffer::create() +{ + Q_D(QOpenGLBuffer); + if (d->guard && d->guard->id()) + return true; + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (ctx) { + delete d->funcs; + d->funcs = new QOpenGLExtensions(ctx); + GLuint bufferId = 0; + d->funcs->glGenBuffers(1, &bufferId); + if (bufferId) { + if (d->guard) + d->guard->free(); + + d->guard = new QOpenGLSharedResourceGuard(ctx, bufferId, freeBufferFunc); + return true; + } + } + return false; +} + +#define ctx QOpenGLContext::currentContext() + +/*! + Returns true if this buffer has been created; false otherwise. + + \sa create(), destroy() +*/ +bool QOpenGLBuffer::isCreated() const +{ + Q_D(const QOpenGLBuffer); + return d->guard && d->guard->id(); +} + +/*! + Destroys this buffer object, including the storage being + used in the GL server. All references to the buffer will + become invalid. +*/ +void QOpenGLBuffer::destroy() +{ + Q_D(QOpenGLBuffer); + if (d->guard) { + d->guard->free(); + d->guard = 0; + } +} + +/*! + Reads the \a count bytes in this buffer starting at \a offset + into \a data. Returns true on success; false if reading from + the buffer is not supported. Buffer reading is not supported + under OpenGL/ES. + + It is assumed that this buffer has been bound to the current context. + + \sa write(), bind() +*/ +bool QOpenGLBuffer::read(int offset, void *data, int count) +{ +#if !defined(QT_OPENGL_ES) + Q_D(QOpenGLBuffer); + if (!d->funcs->hasOpenGLFeature(QOpenGLFunctions::Buffers) || !d->guard->id()) + return false; + while (glGetError() != GL_NO_ERROR) ; // Clear error state. + d->funcs->glGetBufferSubData(d->type, offset, count, data); + return glGetError() == GL_NO_ERROR; +#else + Q_UNUSED(offset); + Q_UNUSED(data); + Q_UNUSED(count); + return false; +#endif +} + +/*! + Replaces the \a count bytes of this buffer starting at \a offset + with the contents of \a data. Any other bytes in the buffer + will be left unmodified. + + It is assumed that create() has been called on this buffer and that + it has been bound to the current context. + + \sa create(), read(), allocate() +*/ +void QOpenGLBuffer::write(int offset, const void *data, int count) +{ +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::allocate(): buffer not created"); +#endif + Q_D(QOpenGLBuffer); + if (d->guard && d->guard->id()) + d->funcs->glBufferSubData(d->type, offset, count, data); +} + +/*! + Allocates \a count bytes of space to the buffer, initialized to + the contents of \a data. Any previous contents will be removed. + + It is assumed that create() has been called on this buffer and that + it has been bound to the current context. + + \sa create(), read(), write() +*/ +void QOpenGLBuffer::allocate(const void *data, int count) +{ +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::allocate(): buffer not created"); +#endif + Q_D(QOpenGLBuffer); + if (d->guard && d->guard->id()) + d->funcs->glBufferData(d->type, count, data, d->actualUsagePattern); +} + +/*! + \fn void QOpenGLBuffer::allocate(int count) + \overload + + Allocates \a count bytes of space to the buffer. Any previous + contents will be removed. + + It is assumed that create() has been called on this buffer and that + it has been bound to the current context. + + \sa create(), write() +*/ + +/*! + Binds the buffer associated with this object to the current + GL context. Returns false if binding was not possible, usually because + type() is not supported on this GL implementation. + + The buffer must be bound to the same QOpenGLContext current when create() + was called, or to another QOpenGLContext that is sharing with it. + Otherwise, false will be returned from this function. + + \sa release(), create() +*/ +bool QOpenGLBuffer::bind() +{ +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::bind(): buffer not created"); +#endif + Q_D(const QOpenGLBuffer); + GLuint bufferId = d->guard ? d->guard->id() : 0; + if (bufferId) { + if (d->guard->group() != QOpenGLContextGroup::currentContextGroup()) { +#ifndef QT_NO_DEBUG + qWarning("QOpenGLBuffer::bind: buffer is not valid in the current context"); +#endif + return false; + } + d->funcs->glBindBuffer(d->type, bufferId); + return true; + } else { + return false; + } +} + +/*! + Releases the buffer associated with this object from the + current GL context. + + This function must be called with the same QOpenGLContext current + as when bind() was called on the buffer. + + \sa bind() +*/ +void QOpenGLBuffer::release() +{ +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::release(): buffer not created"); +#endif + Q_D(const QOpenGLBuffer); + if (d->guard && d->guard->id()) + d->funcs->glBindBuffer(d->type, 0); +} + +#undef ctx + +/*! + Releases the buffer associated with \a type in the current + QOpenGLContext. + + This function is a direct call to \c{glBindBuffer(type, 0)} + for use when the caller does not know which QOpenGLBuffer has + been bound to the context but wants to make sure that it + is released. + + \code + QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer); + \endcode +*/ +void QOpenGLBuffer::release(QOpenGLBuffer::Type type) +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (ctx) { + QOpenGLFunctions(ctx).glBindBuffer(GLenum(type), 0); + } +} + +#define ctx QOpenGLContext::currentContext() + +/*! + Returns the GL identifier associated with this buffer; zero if + the buffer has not been created. + + \sa isCreated() +*/ +GLuint QOpenGLBuffer::bufferId() const +{ + Q_D(const QOpenGLBuffer); + return d->guard ? d->guard->id() : 0; +} + +#ifndef GL_BUFFER_SIZE +#define GL_BUFFER_SIZE 0x8764 +#endif + +/*! + Returns the size of the data in this buffer, for reading operations. + Returns -1 if fetching the buffer size is not supported, or the + buffer has not been created. + + It is assumed that this buffer has been bound to the current context. + + \sa isCreated(), bind() +*/ +int QOpenGLBuffer::size() const +{ + Q_D(const QOpenGLBuffer); + if (!d->guard || !d->guard->id()) + return -1; + GLint value = -1; + d->funcs->glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value); + return value; +} + +/*! + Maps the contents of this buffer into the application's memory + space and returns a pointer to it. Returns null if memory + mapping is not possible. The \a access parameter indicates the + type of access to be performed. + + It is assumed that create() has been called on this buffer and that + it has been bound to the current context. + + This function is only supported under OpenGL/ES if the + \c{GL_OES_mapbuffer} extension is present. + + \sa unmap(), create(), bind() +*/ +void *QOpenGLBuffer::map(QOpenGLBuffer::Access access) +{ + Q_D(QOpenGLBuffer); +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::map(): buffer not created"); +#endif + if (!d->guard || !d->guard->id()) + return 0; +#if 0 + if (!glMapBufferARB) + return 0; + return glMapBufferARB(d->type, access); +#endif + Q_UNUSED(access); + qWarning("QOpenGLBuffer::map(): pending implementation"); + return 0; +} + +/*! + Unmaps the buffer after it was mapped into the application's + memory space with a previous call to map(). Returns true if + the unmap succeeded; false otherwise. + + It is assumed that this buffer has been bound to the current context, + and that it was previously mapped with map(). + + This function is only supported under OpenGL/ES if the + \c{GL_OES_mapbuffer} extension is present. + + \sa map() +*/ +bool QOpenGLBuffer::unmap() +{ + Q_D(QOpenGLBuffer); +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::unmap(): buffer not created"); +#endif + if (!d->guard || !d->guard->id()) + return false; +#if 0 + if (!glUnmapBufferARB) + return false; + return glUnmapBufferARB(d->type) == GL_TRUE; +#endif + qWarning("QOpenGLBuffer::map(): pending implementation"); + return 0; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglbuffer.h b/src/gui/opengl/qopenglbuffer.h new file mode 100644 index 0000000000..52a2c4d640 --- /dev/null +++ b/src/gui/opengl/qopenglbuffer.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLBUFFER_H +#define QOPENGLBUFFER_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QOpenGLBufferPrivate; + +class Q_GUI_EXPORT QOpenGLBuffer +{ +public: + enum Type + { + VertexBuffer = 0x8892, // GL_ARRAY_BUFFER + IndexBuffer = 0x8893, // GL_ELEMENT_ARRAY_BUFFER + PixelPackBuffer = 0x88EB, // GL_PIXEL_PACK_BUFFER + PixelUnpackBuffer = 0x88EC // GL_PIXEL_UNPACK_BUFFER + }; + + QOpenGLBuffer(); + explicit QOpenGLBuffer(QOpenGLBuffer::Type type); + QOpenGLBuffer(const QOpenGLBuffer &other); + ~QOpenGLBuffer(); + + QOpenGLBuffer &operator=(const QOpenGLBuffer &other); + + enum UsagePattern + { + StreamDraw = 0x88E0, // GL_STREAM_DRAW + StreamRead = 0x88E1, // GL_STREAM_READ + StreamCopy = 0x88E2, // GL_STREAM_COPY + StaticDraw = 0x88E4, // GL_STATIC_DRAW + StaticRead = 0x88E5, // GL_STATIC_READ + StaticCopy = 0x88E6, // GL_STATIC_COPY + DynamicDraw = 0x88E8, // GL_DYNAMIC_DRAW + DynamicRead = 0x88E9, // GL_DYNAMIC_READ + DynamicCopy = 0x88EA // GL_DYNAMIC_COPY + }; + + enum Access + { + ReadOnly = 0x88B8, // GL_READ_ONLY + WriteOnly = 0x88B9, // GL_WRITE_ONLY + ReadWrite = 0x88BA // GL_READ_WRITE + }; + + QOpenGLBuffer::Type type() const; + + QOpenGLBuffer::UsagePattern usagePattern() const; + void setUsagePattern(QOpenGLBuffer::UsagePattern value); + + bool create(); + bool isCreated() const; + + void destroy(); + + bool bind(); + void release(); + + static void release(QOpenGLBuffer::Type type); + + GLuint bufferId() const; + + int size() const; + + bool read(int offset, void *data, int count); + void write(int offset, const void *data, int count); + + void allocate(const void *data, int count); + inline void allocate(int count) { allocate(0, count); } + + void *map(QOpenGLBuffer::Access access); + bool unmap(); + +private: + QOpenGLBufferPrivate *d_ptr; + + Q_DECLARE_PRIVATE(QOpenGLBuffer) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/gui/opengl/qopenglcolormap.cpp b/src/gui/opengl/qopenglcolormap.cpp new file mode 100644 index 0000000000..386358ac23 --- /dev/null +++ b/src/gui/opengl/qopenglcolormap.cpp @@ -0,0 +1,297 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QOpenGLColormap + \brief The QOpenGLColormap class is used for installing custom colormaps into + a QOpenGLWidget. + + \module OpenGL + \ingroup painting-3D + \ingroup shared + + QOpenGLColormap provides a platform independent way of specifying and + installing indexed colormaps for a QOpenGLWidget. QOpenGLColormap is + especially useful when using the OpenGL color-index mode. + + Under X11 you must use an X server that supports either a \c + PseudoColor or \c DirectColor visual class. If your X server + currently only provides a \c GrayScale, \c TrueColor, \c + StaticColor or \c StaticGray visual, you will not be able to + allocate colorcells for writing. If this is the case, try setting + your X server to 8 bit mode. It should then provide you with at + least a \c PseudoColor visual. Note that you may experience + colormap flashing if your X server is running in 8 bit mode. + + The size() of the colormap is always set to 256 + colors. Note that under Windows you can also install colormaps + in child widgets. + + This class uses \l{implicit sharing} as a memory and speed + optimization. + + Example of use: + \snippet doc/src/snippets/code/src_opengl_qopenglcolormap.cpp 0 + + \sa QOpenGLWidget::setColormap(), QOpenGLWidget::colormap() +*/ + +/*! + \fn Qt::HANDLE QOpenGLColormap::handle() + + \internal + + Returns the handle for this color map. +*/ + +/*! + \fn void QOpenGLColormap::setHandle(Qt::HANDLE handle) + + \internal + + Sets the handle for this color map to \a handle. +*/ + +#include "qopenglcolormap.h" + +QT_BEGIN_NAMESPACE + +QOpenGLColormap::QOpenGLColormapData QOpenGLColormap::shared_null = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0 }; + +/*! + Construct a QOpenGLColormap. +*/ +QOpenGLColormap::QOpenGLColormap() + : d(&shared_null) +{ + d->ref.ref(); +} + + +/*! + Construct a shallow copy of \a map. +*/ +QOpenGLColormap::QOpenGLColormap(const QOpenGLColormap &map) + : d(map.d) +{ + d->ref.ref(); +} + +/*! + Dereferences the QOpenGLColormap and deletes it if this was the last + reference to it. +*/ +QOpenGLColormap::~QOpenGLColormap() +{ + if (!d->ref.deref()) + cleanup(d); +} + +void QOpenGLColormap::cleanup(QOpenGLColormap::QOpenGLColormapData *x) +{ + delete x->cells; + x->cells = 0; + delete x; +} + +/*! + Assign a shallow copy of \a map to this QOpenGLColormap. +*/ +QOpenGLColormap & QOpenGLColormap::operator=(const QOpenGLColormap &map) +{ + map.d->ref.ref(); + if (!d->ref.deref()) + cleanup(d); + d = map.d; + return *this; +} + +/*! + \fn void QOpenGLColormap::detach() + \internal + + Detaches this QOpenGLColormap from the shared block. +*/ + +void QOpenGLColormap::detach_helper() +{ + QOpenGLColormapData *x = new QOpenGLColormapData; + x->ref = 1; + x->cmapHandle = 0; + x->cells = 0; + if (d->cells) { + x->cells = new QVector(256); + *x->cells = *d->cells; + } + if (!d->ref.deref()) + cleanup(d); + d = x; +} + +/*! + Set cell at index \a idx in the colormap to color \a color. +*/ +void QOpenGLColormap::setEntry(int idx, QRgb color) +{ + detach(); + if (!d->cells) + d->cells = new QVector(256); + d->cells->replace(idx, color); +} + +/*! + Set an array of cells in this colormap. \a count is the number of + colors that should be set, \a colors is the array of colors, and + \a base is the starting index. The first element in \a colors + is set at \a base in the colormap. +*/ +void QOpenGLColormap::setEntries(int count, const QRgb *colors, int base) +{ + detach(); + if (!d->cells) + d->cells = new QVector(256); + + Q_ASSERT_X(colors && base >= 0 && (base + count) <= d->cells->size(), "QOpenGLColormap::setEntries", + "preconditions not met"); + for (int i = 0; i < count; ++i) + setEntry(base + i, colors[i]); +} + +/*! + Returns the QRgb value in the colorcell with index \a idx. +*/ +QRgb QOpenGLColormap::entryRgb(int idx) const +{ + if (d == &shared_null || !d->cells) + return 0; + else + return d->cells->at(idx); +} + +/*! + \overload + + Set the cell with index \a idx in the colormap to color \a color. +*/ +void QOpenGLColormap::setEntry(int idx, const QColor &color) +{ + setEntry(idx, color.rgb()); +} + +/*! + Returns the QRgb value in the colorcell with index \a idx. +*/ +QColor QOpenGLColormap::entryColor(int idx) const +{ + if (d == &shared_null || !d->cells) + return QColor(); + else + return QColor(d->cells->at(idx)); +} + +/*! + Returns true if the colormap is empty or it is not in use + by a QOpenGLWidget; otherwise returns false. + + A colormap with no color values set is considered to be empty. + For historical reasons, a colormap that has color values set + but which is not in use by a QOpenGLWidget is also considered empty. + + Compare size() with zero to determine if the colormap is empty + regardless of whether it is in use by a QOpenGLWidget or not. + + \sa size() +*/ +bool QOpenGLColormap::isEmpty() const +{ + return d == &shared_null || d->cells == 0 || d->cells->size() == 0 || d->cmapHandle == 0; +} + + +/*! + Returns the number of colorcells in the colormap. +*/ +int QOpenGLColormap::size() const +{ + return d->cells ? d->cells->size() : 0; +} + +/*! + Returns the index of the color \a color. If \a color is not in the + map, -1 is returned. +*/ +int QOpenGLColormap::find(QRgb color) const +{ + if (d->cells) + return d->cells->indexOf(color); + return -1; +} + +/*! + Returns the index of the color that is the closest match to color + \a color. +*/ +int QOpenGLColormap::findNearest(QRgb color) const +{ + int idx = find(color); + if (idx >= 0) + return idx; + int mapSize = size(); + int mindist = 200000; + int r = qRed(color); + int g = qGreen(color); + int b = qBlue(color); + int rx, gx, bx, dist; + for (int i = 0; i < mapSize; ++i) { + QRgb ci = d->cells->at(i); + rx = r - qRed(ci); + gx = g - qGreen(ci); + bx = b - qBlue(ci); + dist = rx * rx + gx * gx + bx * bx; // calculate distance + if (dist < mindist) { // minimal? + mindist = dist; + idx = i; + } + } + return idx; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglcolormap.h b/src/gui/opengl/qopenglcolormap.h new file mode 100644 index 0000000000..b05e3f331d --- /dev/null +++ b/src/gui/opengl/qopenglcolormap.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLCOLORMAP_H +#define QOPENGLCOLORMAP_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class Q_GUI_EXPORT QOpenGLColormap +{ +public: + QOpenGLColormap(); + QOpenGLColormap(const QOpenGLColormap &); + ~QOpenGLColormap(); + + QOpenGLColormap &operator=(const QOpenGLColormap &); + + bool isEmpty() const; + int size() const; + void detach(); + + void setEntries(int count, const QRgb * colors, int base = 0); + void setEntry(int idx, QRgb color); + void setEntry(int idx, const QColor & color); + QRgb entryRgb(int idx) const; + QColor entryColor(int idx) const; + int find(QRgb color) const; + int findNearest(QRgb color) const; + +protected: + Qt::HANDLE handle() { return d ? d->cmapHandle : 0; } + void setHandle(Qt::HANDLE ahandle) { d->cmapHandle = ahandle; } + +private: + struct QOpenGLColormapData { + QBasicAtomicInt ref; + QVector *cells; + Qt::HANDLE cmapHandle; + }; + + QOpenGLColormapData *d; + static struct QOpenGLColormapData shared_null; + static void cleanup(QOpenGLColormapData *x); + void detach_helper(); + + friend class QOpenGLWidget; + friend class QOpenGLWidgetPrivate; +}; + +inline void QOpenGLColormap::detach() +{ + if (d->ref != 1) + detach_helper(); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QOPENGLCOLORMAP_H diff --git a/src/gui/opengl/qopenglcustomshaderstage.cpp b/src/gui/opengl/qopenglcustomshaderstage.cpp new file mode 100644 index 0000000000..cbbf318249 --- /dev/null +++ b/src/gui/opengl/qopenglcustomshaderstage.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenglcustomshaderstage_p.h" +#include "qopenglengineshadermanager_p.h" +#include "qpaintengineex_opengl2_p.h" +#include + +QT_BEGIN_NAMESPACE + +class QOpenGLCustomShaderStagePrivate +{ +public: + QOpenGLCustomShaderStagePrivate() : + m_manager(0) {} + + QPointer m_manager; + QByteArray m_source; +}; + + + + +QOpenGLCustomShaderStage::QOpenGLCustomShaderStage() + : d_ptr(new QOpenGLCustomShaderStagePrivate) +{ +} + +QOpenGLCustomShaderStage::~QOpenGLCustomShaderStage() +{ + Q_D(QOpenGLCustomShaderStage); + if (d->m_manager) { + d->m_manager->removeCustomStage(); + d->m_manager->sharedShaders->cleanupCustomStage(this); + } +} + +void QOpenGLCustomShaderStage::setUniformsDirty() +{ + Q_D(QOpenGLCustomShaderStage); + if (d->m_manager) + d->m_manager->setDirty(); // ### Probably a bit overkill! +} + +bool QOpenGLCustomShaderStage::setOnPainter(QPainter* p) +{ + Q_D(QOpenGLCustomShaderStage); + if (p->paintEngine()->type() != QPaintEngine::OpenGL2) { + qWarning("QOpenGLCustomShaderStage::setOnPainter() - paint engine not OpenGL2"); + return false; + } + if (d->m_manager) + qWarning("Custom shader is already set on a painter"); + + QOpenGL2PaintEngineEx *engine = static_cast(p->paintEngine()); + d->m_manager = QOpenGL2PaintEngineExPrivate::shaderManagerForEngine(engine); + Q_ASSERT(d->m_manager); + + d->m_manager->setCustomStage(this); + return true; +} + +void QOpenGLCustomShaderStage::removeFromPainter(QPainter* p) +{ + Q_D(QOpenGLCustomShaderStage); + if (p->paintEngine()->type() != QPaintEngine::OpenGL2) + return; + + QOpenGL2PaintEngineEx *engine = static_cast(p->paintEngine()); + d->m_manager = QOpenGL2PaintEngineExPrivate::shaderManagerForEngine(engine); + Q_ASSERT(d->m_manager); + + // Just set the stage to null, don't call removeCustomStage(). + // This should leave the program in a compiled/linked state + // if the next custom shader stage is this one again. + d->m_manager->setCustomStage(0); + d->m_manager = 0; +} + +QByteArray QOpenGLCustomShaderStage::source() const +{ + Q_D(const QOpenGLCustomShaderStage); + return d->m_source; +} + +// Called by the shader manager if another custom shader is attached or +// the manager is deleted +void QOpenGLCustomShaderStage::setInactive() +{ + Q_D(QOpenGLCustomShaderStage); + d->m_manager = 0; +} + +void QOpenGLCustomShaderStage::setSource(const QByteArray& s) +{ + Q_D(QOpenGLCustomShaderStage); + d->m_source = s; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglcustomshaderstage_p.h b/src/gui/opengl/qopenglcustomshaderstage_p.h new file mode 100644 index 0000000000..36ad307848 --- /dev/null +++ b/src/gui/opengl/qopenglcustomshaderstage_p.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGL_CUSTOM_SHADER_STAGE_H +#define QOPENGL_CUSTOM_SHADER_STAGE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QOpenGLCustomShaderStagePrivate; +class Q_GUI_EXPORT QOpenGLCustomShaderStage +{ + Q_DECLARE_PRIVATE(QOpenGLCustomShaderStage) +public: + QOpenGLCustomShaderStage(); + virtual ~QOpenGLCustomShaderStage(); + virtual void setUniforms(QOpenGLShaderProgram*) {} + + void setUniformsDirty(); + + bool setOnPainter(QPainter*); + void removeFromPainter(QPainter*); + QByteArray source() const; + + void setInactive(); +protected: + void setSource(const QByteArray&); + +private: + QOpenGLCustomShaderStagePrivate* d_ptr; +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp new file mode 100644 index 0000000000..91262dc1ce --- /dev/null +++ b/src/gui/opengl/qopenglengineshadermanager.cpp @@ -0,0 +1,881 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenglengineshadermanager_p.h" +#include "qopenglengineshadersource_p.h" +#include "qpaintengineex_opengl2_p.h" +#include "qopenglshadercache_p.h" + +#include +#include + +#if defined(QT_DEBUG) +#include +#endif + +// #define QT_GL_SHARED_SHADER_DEBUG + +QT_BEGIN_NAMESPACE + +class QOpenGLEngineSharedShadersResource : public QOpenGLSharedResource +{ +public: + QOpenGLEngineSharedShadersResource(QOpenGLContext *ctx) + : QOpenGLSharedResource(ctx->shareGroup()) + , m_shaders(new QOpenGLEngineSharedShaders(ctx)) + { + } + + ~QOpenGLEngineSharedShadersResource() + { + delete m_shaders; + } + + void invalidateResource() + { + delete m_shaders; + m_shaders = 0; + } + + void freeResource(QOpenGLContext *) + { + } + + QOpenGLEngineSharedShaders *shaders() const { return m_shaders; } + +private: + QOpenGLEngineSharedShaders *m_shaders; +}; + +class QOpenGLShaderStorage +{ +public: + QOpenGLEngineSharedShaders *shadersForThread(QOpenGLContext *context) { + QOpenGLMultiGroupSharedResource *&shaders = m_storage.localData(); + if (!shaders) + shaders = new QOpenGLMultiGroupSharedResource; + QOpenGLEngineSharedShadersResource *resource = + shaders->value(context); + return resource ? resource->shaders() : 0; + } + +private: + QThreadStorage m_storage; +}; + +Q_GLOBAL_STATIC(QOpenGLShaderStorage, qt_shader_storage); + +QOpenGLEngineSharedShaders *QOpenGLEngineSharedShaders::shadersForContext(QOpenGLContext *context) +{ + return qt_shader_storage()->shadersForThread(context); +} + +const char* QOpenGLEngineSharedShaders::qShaderSnippets[] = { + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0 +}; + +QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) + : blitShaderProg(0) + , simpleShaderProg(0) +{ + +/* + Rather than having the shader source array statically initialised, it is initialised + here instead. This is to allow new shader names to be inserted or existing names moved + around without having to change the order of the glsl strings. It is hoped this will + make future hard-to-find runtime bugs more obvious and generally give more solid code. +*/ + static bool snippetsPopulated = false; + if (!snippetsPopulated) { + + const char** code = qShaderSnippets; // shortcut + + code[MainVertexShader] = qopenglslMainVertexShader; + code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader; + code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader; + + code[UntransformedPositionVertexShader] = qopenglslUntransformedPositionVertexShader; + code[PositionOnlyVertexShader] = qopenglslPositionOnlyVertexShader; + code[ComplexGeometryPositionOnlyVertexShader] = qopenglslComplexGeometryPositionOnlyVertexShader; + code[PositionWithPatternBrushVertexShader] = qopenglslPositionWithPatternBrushVertexShader; + code[PositionWithLinearGradientBrushVertexShader] = qopenglslPositionWithLinearGradientBrushVertexShader; + code[PositionWithConicalGradientBrushVertexShader] = qopenglslPositionWithConicalGradientBrushVertexShader; + code[PositionWithRadialGradientBrushVertexShader] = qopenglslPositionWithRadialGradientBrushVertexShader; + code[PositionWithTextureBrushVertexShader] = qopenglslPositionWithTextureBrushVertexShader; + code[AffinePositionWithPatternBrushVertexShader] = qopenglslAffinePositionWithPatternBrushVertexShader; + code[AffinePositionWithLinearGradientBrushVertexShader] = qopenglslAffinePositionWithLinearGradientBrushVertexShader; + code[AffinePositionWithConicalGradientBrushVertexShader] = qopenglslAffinePositionWithConicalGradientBrushVertexShader; + code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader; + code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader; + + code[MainFragmentShader_CMO] = qopenglslMainFragmentShader_CMO; + code[MainFragmentShader_CM] = qopenglslMainFragmentShader_CM; + code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO; + code[MainFragmentShader_M] = qopenglslMainFragmentShader_M; + code[MainFragmentShader_CO] = qopenglslMainFragmentShader_CO; + code[MainFragmentShader_C] = qopenglslMainFragmentShader_C; + code[MainFragmentShader_O] = qopenglslMainFragmentShader_O; + code[MainFragmentShader] = qopenglslMainFragmentShader; + code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays; + + code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader; + code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader; + code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader; + code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended + code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader; + code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader; + code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader; + code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader; + code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader; + code[RadialGradientBrushSrcFragmentShader] = qopenglslRadialGradientBrushSrcFragmentShader; + code[ConicalGradientBrushSrcFragmentShader] = qopenglslConicalGradientBrushSrcFragmentShader; + code[ShockingPinkSrcFragmentShader] = qopenglslShockingPinkSrcFragmentShader; + + code[NoMaskFragmentShader] = ""; + code[MaskFragmentShader] = qopenglslMaskFragmentShader; + code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1; + code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2; + code[RgbMaskWithGammaFragmentShader] = ""; //### + + code[NoCompositionModeFragmentShader] = ""; + code[MultiplyCompositionModeFragmentShader] = ""; //### + code[ScreenCompositionModeFragmentShader] = ""; //### + code[OverlayCompositionModeFragmentShader] = ""; //### + code[DarkenCompositionModeFragmentShader] = ""; //### + code[LightenCompositionModeFragmentShader] = ""; //### + code[ColorDodgeCompositionModeFragmentShader] = ""; //### + code[ColorBurnCompositionModeFragmentShader] = ""; //### + code[HardLightCompositionModeFragmentShader] = ""; //### + code[SoftLightCompositionModeFragmentShader] = ""; //### + code[DifferenceCompositionModeFragmentShader] = ""; //### + code[ExclusionCompositionModeFragmentShader] = ""; //### + +#if defined(QT_DEBUG) + // Check that all the elements have been filled: + for (int i = 0; i < TotalSnippetCount; ++i) { + if (qShaderSnippets[i] == 0) { + qFatal("Shader snippet for %s (#%d) is missing!", + snippetNameStr(SnippetName(i)).constData(), i); + } + } +#endif + snippetsPopulated = true; + } + + QOpenGLShader* fragShader; + QOpenGLShader* vertexShader; + QByteArray vertexSource; + QByteArray fragSource; + + // Compile up the simple shader: + vertexSource.append(qShaderSnippets[MainVertexShader]); + vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]); + + fragSource.append(qShaderSnippets[MainFragmentShader]); + fragSource.append(qShaderSnippets[ShockingPinkSrcFragmentShader]); + + simpleShaderProg = new QOpenGLShaderProgram; + + CachedShader simpleShaderCache(fragSource, vertexSource); + + bool inCache = simpleShaderCache.load(simpleShaderProg, context); + + if (!inCache) { + vertexShader = new QOpenGLShader(QOpenGLShader::Vertex); + shaders.append(vertexShader); + if (!vertexShader->compileSourceCode(vertexSource)) + qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile"); + + fragShader = new QOpenGLShader(QOpenGLShader::Fragment); + shaders.append(fragShader); + if (!fragShader->compileSourceCode(fragSource)) + qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile"); + + simpleShaderProg->addShader(vertexShader); + simpleShaderProg->addShader(fragShader); + + simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); + simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); + simpleShaderProg->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR); + } + + simpleShaderProg->link(); + + if (simpleShaderProg->isLinked()) { + if (!inCache) + simpleShaderCache.store(simpleShaderProg, context); + } else { + qCritical() << "Errors linking simple shader:" + << simpleShaderProg->log(); + } + + // Compile the blit shader: + vertexSource.clear(); + vertexSource.append(qShaderSnippets[MainWithTexCoordsVertexShader]); + vertexSource.append(qShaderSnippets[UntransformedPositionVertexShader]); + + fragSource.clear(); + fragSource.append(qShaderSnippets[MainFragmentShader]); + fragSource.append(qShaderSnippets[ImageSrcFragmentShader]); + + blitShaderProg = new QOpenGLShaderProgram; + + CachedShader blitShaderCache(fragSource, vertexSource); + + inCache = blitShaderCache.load(blitShaderProg, context); + + if (!inCache) { + vertexShader = new QOpenGLShader(QOpenGLShader::Vertex); + shaders.append(vertexShader); + if (!vertexShader->compileSourceCode(vertexSource)) + qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile"); + + fragShader = new QOpenGLShader(QOpenGLShader::Fragment); + shaders.append(fragShader); + if (!fragShader->compileSourceCode(fragSource)) + qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile"); + + blitShaderProg->addShader(vertexShader); + blitShaderProg->addShader(fragShader); + + blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + } + + blitShaderProg->link(); + if (blitShaderProg->isLinked()) { + if (!inCache) + blitShaderCache.store(blitShaderProg, context); + } else { + qCritical() << "Errors linking blit shader:" + << blitShaderProg->log(); + } + +#ifdef QT_GL_SHARED_SHADER_DEBUG + qDebug(" -> QOpenGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread()); +#endif +} + +QOpenGLEngineSharedShaders::~QOpenGLEngineSharedShaders() +{ +#ifdef QT_GL_SHARED_SHADER_DEBUG + qDebug(" -> ~QOpenGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread()); +#endif + qDeleteAll(shaders); + shaders.clear(); + + qDeleteAll(cachedPrograms); + cachedPrograms.clear(); + + if (blitShaderProg) { + delete blitShaderProg; + blitShaderProg = 0; + } + + if (simpleShaderProg) { + delete simpleShaderProg; + simpleShaderProg = 0; + } +} + +#if defined (QT_DEBUG) +QByteArray QOpenGLEngineSharedShaders::snippetNameStr(SnippetName name) +{ + QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("SnippetName")); + return QByteArray(m.valueToKey(name)); +} +#endif + +// The address returned here will only be valid until next time this function is called. +// The program is return bound. +QOpenGLEngineShaderProg *QOpenGLEngineSharedShaders::findProgramInCache(const QOpenGLEngineShaderProg &prog) +{ + for (int i = 0; i < cachedPrograms.size(); ++i) { + QOpenGLEngineShaderProg *cachedProg = cachedPrograms[i]; + if (*cachedProg == prog) { + // Move the program to the top of the list as a poor-man's cache algo + cachedPrograms.move(i, 0); + cachedProg->program->bind(); + return cachedProg; + } + } + + QScopedPointer newProg; + + do { + QByteArray fragSource; + // Insert the custom stage before the srcPixel shader to work around an ATI driver bug + // where you cannot forward declare a function that takes a sampler as argument. + if (prog.srcPixelFragShader == CustomImageSrcFragmentShader) + fragSource.append(prog.customStageSource); + fragSource.append(qShaderSnippets[prog.mainFragShader]); + fragSource.append(qShaderSnippets[prog.srcPixelFragShader]); + if (prog.compositionFragShader) + fragSource.append(qShaderSnippets[prog.compositionFragShader]); + if (prog.maskFragShader) + fragSource.append(qShaderSnippets[prog.maskFragShader]); + + QByteArray vertexSource; + vertexSource.append(qShaderSnippets[prog.mainVertexShader]); + vertexSource.append(qShaderSnippets[prog.positionVertexShader]); + + QScopedPointer shaderProgram(new QOpenGLShaderProgram); + + CachedShader shaderCache(fragSource, vertexSource); + bool inCache = shaderCache.load(shaderProgram.data(), QOpenGLContext::currentContext()); + + if (!inCache) { + + QScopedPointer fragShader(new QOpenGLShader(QOpenGLShader::Fragment)); + QByteArray description; +#if defined(QT_DEBUG) + // Name the shader for easier debugging + description.append("Fragment shader: main="); + description.append(snippetNameStr(prog.mainFragShader)); + description.append(", srcPixel="); + description.append(snippetNameStr(prog.srcPixelFragShader)); + if (prog.compositionFragShader) { + description.append(", composition="); + description.append(snippetNameStr(prog.compositionFragShader)); + } + if (prog.maskFragShader) { + description.append(", mask="); + description.append(snippetNameStr(prog.maskFragShader)); + } + fragShader->setObjectName(QString::fromLatin1(description)); +#endif + if (!fragShader->compileSourceCode(fragSource)) { + qWarning() << "Warning:" << description << "failed to compile!"; + break; + } + + QScopedPointer vertexShader(new QOpenGLShader(QOpenGLShader::Vertex)); +#if defined(QT_DEBUG) + // Name the shader for easier debugging + description.clear(); + description.append("Vertex shader: main="); + description.append(snippetNameStr(prog.mainVertexShader)); + description.append(", position="); + description.append(snippetNameStr(prog.positionVertexShader)); + vertexShader->setObjectName(QString::fromLatin1(description)); +#endif + if (!vertexShader->compileSourceCode(vertexSource)) { + qWarning() << "Warning:" << description << "failed to compile!"; + break; + } + + shaders.append(vertexShader.data()); + shaders.append(fragShader.data()); + shaderProgram->addShader(vertexShader.take()); + shaderProgram->addShader(fragShader.take()); + + // We have to bind the vertex attribute names before the program is linked: + shaderProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + if (prog.useTextureCoords) + shaderProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + if (prog.useOpacityAttribute) + shaderProgram->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR); + if (prog.usePmvMatrixAttribute) { + shaderProgram->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); + shaderProgram->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); + shaderProgram->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR); + } + } + + newProg.reset(new QOpenGLEngineShaderProg(prog)); + newProg->program = shaderProgram.take(); + + newProg->program->link(); + if (newProg->program->isLinked()) { + if (!inCache) + shaderCache.store(newProg->program, QOpenGLContext::currentContext()); + } else { + QLatin1String none("none"); + QLatin1String br("\n"); + QString error; + error = QLatin1String("Shader program failed to link,"); +#if defined(QT_DEBUG) + error += QLatin1String("\n Shaders Used:\n"); + for (int i = 0; i < newProg->program->shaders().count(); ++i) { + QOpenGLShader *shader = newProg->program->shaders().at(i); + error += QLatin1String(" ") + shader->objectName() + QLatin1String(": \n") + + QLatin1String(shader->sourceCode()) + br; + } +#endif + error += QLatin1String(" Error Log:\n") + + QLatin1String(" ") + newProg->program->log(); + qWarning() << error; + break; + } + + newProg->program->bind(); + + if (newProg->maskFragShader != QOpenGLEngineSharedShaders::NoMaskFragmentShader) { + GLuint location = newProg->program->uniformLocation("maskTexture"); + newProg->program->setUniformValue(location, QT_MASK_TEXTURE_UNIT); + } + + if (cachedPrograms.count() > 30) { + // The cache is full, so delete the last 5 programs in the list. + // These programs will be least used, as a program us bumped to + // the top of the list when it's used. + for (int i = 0; i < 5; ++i) { + delete cachedPrograms.last(); + cachedPrograms.removeLast(); + } + } + + cachedPrograms.insert(0, newProg.data()); + } while (false); + + return newProg.take(); +} + +void QOpenGLEngineSharedShaders::cleanupCustomStage(QOpenGLCustomShaderStage* stage) +{ + // Remove any shader programs which has this as the custom shader src: + for (int i = 0; i < cachedPrograms.size(); ++i) { + QOpenGLEngineShaderProg *cachedProg = cachedPrograms[i]; + if (cachedProg->customStageSource == stage->source()) { + delete cachedProg; + cachedPrograms.removeAt(i); + i--; + } + } +} + + +QOpenGLEngineShaderManager::QOpenGLEngineShaderManager(QOpenGLContext* context) + : ctx(context), + shaderProgNeedsChanging(true), + complexGeometry(false), + srcPixelType(Qt::NoBrush), + opacityMode(NoOpacity), + maskType(NoMask), + compositionMode(QPainter::CompositionMode_SourceOver), + customSrcStage(0), + currentShaderProg(0) +{ + sharedShaders = QOpenGLEngineSharedShaders::shadersForContext(context); +} + +QOpenGLEngineShaderManager::~QOpenGLEngineShaderManager() +{ + //### + removeCustomStage(); +} + +GLuint QOpenGLEngineShaderManager::getUniformLocation(Uniform id) +{ + if (!currentShaderProg) + return 0; + + QVector &uniformLocations = currentShaderProg->uniformLocations; + if (uniformLocations.isEmpty()) + uniformLocations.fill(GLuint(-1), NumUniforms); + + static const char *uniformNames[] = { + "imageTexture", + "patternColor", + "globalOpacity", + "depth", + "maskTexture", + "fragmentColor", + "linearData", + "angle", + "halfViewportSize", + "fmp", + "fmp2_m_radius2", + "inverse_2_fmp2_m_radius2", + "sqrfr", + "bradius", + "invertedTextureSize", + "brushTransform", + "brushTexture", + "matrix" + }; + + if (uniformLocations.at(id) == GLuint(-1)) + uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformNames[id]); + + return uniformLocations.at(id); +} + + +void QOpenGLEngineShaderManager::optimiseForBrushTransform(QTransform::TransformationType transformType) +{ + Q_UNUSED(transformType); // Currently ignored +} + +void QOpenGLEngineShaderManager::setDirty() +{ + shaderProgNeedsChanging = true; +} + +void QOpenGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style) +{ + Q_ASSERT(style != Qt::NoBrush); + if (srcPixelType == PixelSrcType(style)) + return; + + srcPixelType = style; + shaderProgNeedsChanging = true; //### +} + +void QOpenGLEngineShaderManager::setSrcPixelType(PixelSrcType type) +{ + if (srcPixelType == type) + return; + + srcPixelType = type; + shaderProgNeedsChanging = true; //### +} + +void QOpenGLEngineShaderManager::setOpacityMode(OpacityMode mode) +{ + if (opacityMode == mode) + return; + + opacityMode = mode; + shaderProgNeedsChanging = true; //### +} + +void QOpenGLEngineShaderManager::setMaskType(MaskType type) +{ + if (maskType == type) + return; + + maskType = type; + shaderProgNeedsChanging = true; //### +} + +void QOpenGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode) +{ + if (compositionMode == mode) + return; + + compositionMode = mode; + shaderProgNeedsChanging = true; //### +} + +void QOpenGLEngineShaderManager::setCustomStage(QOpenGLCustomShaderStage* stage) +{ + if (customSrcStage) + removeCustomStage(); + customSrcStage = stage; + shaderProgNeedsChanging = true; +} + +void QOpenGLEngineShaderManager::removeCustomStage() +{ + if (customSrcStage) + customSrcStage->setInactive(); + customSrcStage = 0; + shaderProgNeedsChanging = true; +} + +QOpenGLShaderProgram* QOpenGLEngineShaderManager::currentProgram() +{ + if (currentShaderProg) + return currentShaderProg->program; + else + return sharedShaders->simpleProgram(); +} + +void QOpenGLEngineShaderManager::useSimpleProgram() +{ + sharedShaders->simpleProgram()->bind(); + QOpenGLContextPrivate* ctx_d = ctx->d_func(); + Q_UNUSED(ctx_d); + + QOpenGL2PaintEngineEx *active_engine = static_cast(ctx_d->active_engine); + + active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); + active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false); + active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); + + shaderProgNeedsChanging = true; +} + +void QOpenGLEngineShaderManager::useBlitProgram() +{ + sharedShaders->blitProgram()->bind(); + QOpenGLContextPrivate* ctx_d = ctx->d_func(); + QOpenGL2PaintEngineEx *active_engine = static_cast(ctx_d->active_engine); + active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); + active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true); + active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); + shaderProgNeedsChanging = true; +} + +QOpenGLShaderProgram* QOpenGLEngineShaderManager::simpleProgram() +{ + return sharedShaders->simpleProgram(); +} + +QOpenGLShaderProgram* QOpenGLEngineShaderManager::blitProgram() +{ + return sharedShaders->blitProgram(); +} + + + +// Select & use the correct shader program using the current state. +// Returns true if program needed changing. +bool QOpenGLEngineShaderManager::useCorrectShaderProg() +{ + if (!shaderProgNeedsChanging) + return false; + + bool useCustomSrc = customSrcStage != 0; + if (useCustomSrc && srcPixelType != QOpenGLEngineShaderManager::ImageSrc && srcPixelType != Qt::TexturePattern) { + useCustomSrc = false; + qWarning("QOpenGLEngineShaderManager - Ignoring custom shader stage for non image src"); + } + + QOpenGLEngineShaderProg requiredProgram; + + bool texCoords = false; + + // Choose vertex shader shader position function (which typically also sets + // varyings) and the source pixel (srcPixel) fragment shader function: + requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::InvalidSnippetName; + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::InvalidSnippetName; + bool isAffine = brushTransform.isAffine(); + if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) { + if (isAffine) + requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader; + else + requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionWithPatternBrushVertexShader; + + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::PatternBrushSrcFragmentShader; + } + else switch (srcPixelType) { + default: + case Qt::NoBrush: + qFatal("QOpenGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set"); + break; + case QOpenGLEngineShaderManager::ImageSrc: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ImageSrcFragmentShader; + requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; + texCoords = true; + break; + case QOpenGLEngineShaderManager::NonPremultipliedImageSrc: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader; + requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; + texCoords = true; + break; + case QOpenGLEngineShaderManager::PatternSrc: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ImageSrcWithPatternFragmentShader; + requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; + texCoords = true; + break; + case QOpenGLEngineShaderManager::TextureSrcWithPattern: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader; + requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader + : QOpenGLEngineSharedShaders::PositionWithTextureBrushVertexShader; + break; + case Qt::SolidPattern: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::SolidBrushSrcFragmentShader; + requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; + break; + case Qt::LinearGradientPattern: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader; + requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader + : QOpenGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader; + break; + case Qt::ConicalGradientPattern: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader; + requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader + : QOpenGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader; + break; + case Qt::RadialGradientPattern: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader; + requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader + : QOpenGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader; + break; + case Qt::TexturePattern: + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::TextureBrushSrcFragmentShader; + requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader + : QOpenGLEngineSharedShaders::PositionWithTextureBrushVertexShader; + break; + }; + + if (useCustomSrc) { + requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::CustomImageSrcFragmentShader; + requiredProgram.customStageSource = customSrcStage->source(); + } + + const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus; + const bool hasMask = maskType != QOpenGLEngineShaderManager::NoMask; + + // Choose fragment shader main function: + if (opacityMode == AttributeOpacity) { + Q_ASSERT(!hasCompose && !hasMask); + requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_ImageArrays; + } else { + bool useGlobalOpacity = (opacityMode == UniformOpacity); + if (hasCompose && hasMask && useGlobalOpacity) + requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CMO; + if (hasCompose && hasMask && !useGlobalOpacity) + requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CM; + if (!hasCompose && hasMask && useGlobalOpacity) + requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_MO; + if (!hasCompose && hasMask && !useGlobalOpacity) + requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_M; + if (hasCompose && !hasMask && useGlobalOpacity) + requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_CO; + if (hasCompose && !hasMask && !useGlobalOpacity) + requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_C; + if (!hasCompose && !hasMask && useGlobalOpacity) + requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_O; + if (!hasCompose && !hasMask && !useGlobalOpacity) + requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader; + } + + if (hasMask) { + if (maskType == PixelMask) { + requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::MaskFragmentShader; + texCoords = true; + } else if (maskType == SubPixelMaskPass1) { + requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::RgbMaskFragmentShaderPass1; + texCoords = true; + } else if (maskType == SubPixelMaskPass2) { + requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::RgbMaskFragmentShaderPass2; + texCoords = true; + } else if (maskType == SubPixelWithGammaMask) { + requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::RgbMaskWithGammaFragmentShader; + texCoords = true; + } else { + qCritical("QOpenGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type"); + } + } else { + requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::NoMaskFragmentShader; + } + + if (hasCompose) { + switch (compositionMode) { + case QPainter::CompositionMode_Multiply: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::MultiplyCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Screen: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ScreenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Overlay: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::OverlayCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Darken: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::DarkenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Lighten: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::LightenCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_ColorDodge: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_ColorBurn: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_HardLight: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::HardLightCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_SoftLight: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::SoftLightCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Difference: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::DifferenceCompositionModeFragmentShader; + break; + case QPainter::CompositionMode_Exclusion: + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ExclusionCompositionModeFragmentShader; + break; + default: + qWarning("QOpenGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode"); + } + } else { + requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::NoCompositionModeFragmentShader; + } + + // Choose vertex shader main function + if (opacityMode == AttributeOpacity) { + Q_ASSERT(texCoords); + requiredProgram.mainVertexShader = QOpenGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader; + } else if (texCoords) { + requiredProgram.mainVertexShader = QOpenGLEngineSharedShaders::MainWithTexCoordsVertexShader; + } else { + requiredProgram.mainVertexShader = QOpenGLEngineSharedShaders::MainVertexShader; + } + requiredProgram.useTextureCoords = texCoords; + requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity); + if (complexGeometry && srcPixelType == Qt::SolidPattern) { + requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::ComplexGeometryPositionOnlyVertexShader; + requiredProgram.usePmvMatrixAttribute = false; + } else { + requiredProgram.usePmvMatrixAttribute = true; + + // Force complexGeometry off, since we currently don't support that mode for + // non-solid brushes + complexGeometry = false; + } + + // At this point, requiredProgram is fully populated so try to find the program in the cache + currentShaderProg = sharedShaders->findProgramInCache(requiredProgram); + + if (currentShaderProg && useCustomSrc) { + customSrcStage->setUniforms(currentShaderProg->program); + } + + // Make sure all the vertex attribute arrays the program uses are enabled (and the ones it + // doesn't use are disabled) + QOpenGLContextPrivate* ctx_d = ctx->d_func(); + QOpenGL2PaintEngineEx *active_engine = static_cast(ctx_d->active_engine); + active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); + active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, currentShaderProg && currentShaderProg->useTextureCoords); + active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, currentShaderProg && currentShaderProg->useOpacityAttribute); + + shaderProgNeedsChanging = false; + return true; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglengineshadermanager_p.h b/src/gui/opengl/qopenglengineshadermanager_p.h new file mode 100644 index 0000000000..1dcc4fe7a7 --- /dev/null +++ b/src/gui/opengl/qopenglengineshadermanager_p.h @@ -0,0 +1,514 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +/* + VERTEX SHADERS + ============== + + Vertex shaders are specified as multiple (partial) shaders. On desktop, + this works fine. On ES, QOpenGLShader & QOpenGLShaderProgram will make partial + shaders work by concatenating the source in each QOpenGLShader and compiling + it as a single shader. This is abstracted nicely by QOpenGLShaderProgram and + the GL2 engine doesn't need to worry about it. + + Generally, there's two vertex shader objects. The position shaders are + the ones which set gl_Position. There's also two "main" vertex shaders, + one which just calls the position shader and another which also passes + through some texture coordinates from a vertex attribute array to a + varying. These texture coordinates are used for mask position in text + rendering and for the source coordinates in drawImage/drawPixmap. There's + also a "Simple" vertex shader for rendering a solid colour (used to render + into the stencil buffer where the actual colour value is discarded). + + The position shaders for brushes look scary. This is because many of the + calculations which logically belong in the fragment shader have been moved + into the vertex shader to improve performance. This is why the position + calculation is in a separate shader. Not only does it calculate the + position, but it also calculates some data to be passed to the fragment + shader as a varying. It is optimal to move as much of the calculation as + possible into the vertex shader as this is executed less often. + + The varyings passed to the fragment shaders are interpolated (which is + cheap). Unfortunately, GL will apply perspective correction to the + interpolation calusing errors. To get around this, the vertex shader must + apply perspective correction itself and set the w-value of gl_Position to + zero. That way, GL will be tricked into thinking it doesn't need to apply a + perspective correction and use linear interpolation instead (which is what + we want). Of course, if the brush transform is affeine, no perspective + correction is needed and a simpler vertex shader can be used instead. + + So there are the following "main" vertex shaders: + qopenglslMainVertexShader + qopenglslMainWithTexCoordsVertexShader + + And the the following position vertex shaders: + qopenglslPositionOnlyVertexShader + qopenglslPositionWithTextureBrushVertexShader + qopenglslPositionWithPatternBrushVertexShader + qopenglslPositionWithLinearGradientBrushVertexShader + qopenglslPositionWithRadialGradientBrushVertexShader + qopenglslPositionWithConicalGradientBrushVertexShader + qopenglslAffinePositionWithTextureBrushVertexShader + qopenglslAffinePositionWithPatternBrushVertexShader + qopenglslAffinePositionWithLinearGradientBrushVertexShader + qopenglslAffinePositionWithRadialGradientBrushVertexShader + qopenglslAffinePositionWithConicalGradientBrushVertexShader + + Leading to 23 possible vertex shaders + + + FRAGMENT SHADERS + ================ + + Fragment shaders are also specified as multiple (partial) shaders. The + different fragment shaders represent the different stages in Qt's fragment + pipeline. There are 1-3 stages in this pipeline: First stage is to get the + fragment's colour value. The next stage is to get the fragment's mask value + (coverage value for anti-aliasing) and the final stage is to blend the + incoming fragment with the background (for composition modes not supported + by GL). + + Of these, the first stage will always be present. If Qt doesn't need to + apply anti-aliasing (because it's off or handled by multisampling) then + the coverage value doesn't need to be applied. (Note: There are two types + of mask, one for regular anti-aliasing and one for sub-pixel anti- + aliasing.) If the composition mode is one which GL supports natively then + the blending stage doesn't need to be applied. + + As eash stage can have multiple implementations, they are abstracted as + GLSL function calls with the following signatures: + + Brushes & image drawing are implementations of "qcolorp vec4 srcPixel()": + qopenglslImageSrcFragShader + qopenglslImageSrcWithPatternFragShader + qopenglslNonPremultipliedImageSrcFragShader + qopenglslSolidBrushSrcFragShader + qopenglslTextureBrushSrcFragShader + qopenglslTextureBrushWithPatternFragShader + qopenglslPatternBrushSrcFragShader + qopenglslLinearGradientBrushSrcFragShader + qopenglslRadialGradientBrushSrcFragShader + qopenglslConicalGradientBrushSrcFragShader + NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied + + Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)": + qopenglslMaskFragmentShader + qopenglslRgbMaskFragmentShaderPass1 + qopenglslRgbMaskFragmentShaderPass2 + qopenglslRgbMaskWithGammaFragmentShader + + Composition modes are "qcolorp vec4 compose(qcolorp vec4 src)": + qopenglslColorBurnCompositionModeFragmentShader + qopenglslColorDodgeCompositionModeFragmentShader + qopenglslDarkenCompositionModeFragmentShader + qopenglslDifferenceCompositionModeFragmentShader + qopenglslExclusionCompositionModeFragmentShader + qopenglslHardLightCompositionModeFragmentShader + qopenglslLightenCompositionModeFragmentShader + qopenglslMultiplyCompositionModeFragmentShader + qopenglslOverlayCompositionModeFragmentShader + qopenglslScreenCompositionModeFragmentShader + qopenglslSoftLightCompositionModeFragmentShader + + + Note: In the future, some GLSL compilers will support an extension allowing + a new 'color' precision specifier. To support this, qcolorp is used for + all color components so it can be defined to colorp or lowp depending upon + the implementation. + + So there are differnt frament shader main functions, depending on the + number & type of pipelines the fragment needs to go through. + + The choice of which main() fragment shader string to use depends on: + - Use of global opacity + - Brush style (some brushes apply opacity themselves) + - Use & type of mask (TODO: Need to support high quality anti-aliasing & text) + - Use of non-GL Composition mode + + Leading to the following fragment shader main functions: + gl_FragColor = compose(applyMask(srcPixel()*globalOpacity)); + gl_FragColor = compose(applyMask(srcPixel())); + gl_FragColor = applyMask(srcPixel()*globalOpacity); + gl_FragColor = applyMask(srcPixel()); + gl_FragColor = compose(srcPixel()*globalOpacity); + gl_FragColor = compose(srcPixel()); + gl_FragColor = srcPixel()*globalOpacity; + gl_FragColor = srcPixel(); + + Called: + qopenglslMainFragmentShader_CMO + qopenglslMainFragmentShader_CM + qopenglslMainFragmentShader_MO + qopenglslMainFragmentShader_M + qopenglslMainFragmentShader_CO + qopenglslMainFragmentShader_C + qopenglslMainFragmentShader_O + qopenglslMainFragmentShader + + Where: + M = Mask + C = Composition + O = Global Opacity + + + CUSTOM SHADER CODE + ================== + + The use of custom shader code is supported by the engine for drawImage and + drawPixmap calls. This is implemented via hooks in the fragment pipeline. + + The custom shader is passed to the engine as a partial fragment shader + (QOpenGLCustomShaderStage). The shader will implement a pre-defined method name + which Qt's fragment pipeline will call: + + lowp vec4 customShader(lowp sampler2d imageTexture, highp vec2 textureCoords) + + The provided src and srcCoords parameters can be used to sample from the + source image. + + Transformations, clipping, opacity, and composition modes set using QPainter + will be respected when using the custom shader hook. +*/ + +#ifndef QOPENGLENGINE_SHADER_MANAGER_H +#define QOPENGLENGINE_SHADER_MANAGER_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + + +/* +struct QOpenGLEngineCachedShaderProg +{ + QOpenGLEngineCachedShaderProg(QOpenGLEngineShaderManager::ShaderName vertexMain, + QOpenGLEngineShaderManager::ShaderName vertexPosition, + QOpenGLEngineShaderManager::ShaderName fragMain, + QOpenGLEngineShaderManager::ShaderName pixelSrc, + QOpenGLEngineShaderManager::ShaderName mask, + QOpenGLEngineShaderManager::ShaderName composition); + + int cacheKey; + QOpenGLShaderProgram* program; +} +*/ + +static const GLuint QT_VERTEX_COORDS_ATTR = 0; +static const GLuint QT_TEXTURE_COORDS_ATTR = 1; +static const GLuint QT_OPACITY_ATTR = 2; +static const GLuint QT_PMV_MATRIX_1_ATTR = 3; +static const GLuint QT_PMV_MATRIX_2_ATTR = 4; +static const GLuint QT_PMV_MATRIX_3_ATTR = 5; + +class QOpenGLEngineShaderProg; + +class Q_GUI_EXPORT QOpenGLEngineSharedShaders +{ + Q_GADGET +public: + + enum SnippetName { + MainVertexShader, + MainWithTexCoordsVertexShader, + MainWithTexCoordsAndOpacityVertexShader, + + // UntransformedPositionVertexShader must be first in the list: + UntransformedPositionVertexShader, + PositionOnlyVertexShader, + ComplexGeometryPositionOnlyVertexShader, + PositionWithPatternBrushVertexShader, + PositionWithLinearGradientBrushVertexShader, + PositionWithConicalGradientBrushVertexShader, + PositionWithRadialGradientBrushVertexShader, + PositionWithTextureBrushVertexShader, + AffinePositionWithPatternBrushVertexShader, + AffinePositionWithLinearGradientBrushVertexShader, + AffinePositionWithConicalGradientBrushVertexShader, + AffinePositionWithRadialGradientBrushVertexShader, + AffinePositionWithTextureBrushVertexShader, + + // MainFragmentShader_CMO must be first in the list: + MainFragmentShader_CMO, + MainFragmentShader_CM, + MainFragmentShader_MO, + MainFragmentShader_M, + MainFragmentShader_CO, + MainFragmentShader_C, + MainFragmentShader_O, + MainFragmentShader, + MainFragmentShader_ImageArrays, + + // ImageSrcFragmentShader must be first in the list:: + ImageSrcFragmentShader, + ImageSrcWithPatternFragmentShader, + NonPremultipliedImageSrcFragmentShader, + CustomImageSrcFragmentShader, + SolidBrushSrcFragmentShader, + TextureBrushSrcFragmentShader, + TextureBrushSrcWithPatternFragmentShader, + PatternBrushSrcFragmentShader, + LinearGradientBrushSrcFragmentShader, + RadialGradientBrushSrcFragmentShader, + ConicalGradientBrushSrcFragmentShader, + ShockingPinkSrcFragmentShader, + + // NoMaskFragmentShader must be first in the list: + NoMaskFragmentShader, + MaskFragmentShader, + RgbMaskFragmentShaderPass1, + RgbMaskFragmentShaderPass2, + RgbMaskWithGammaFragmentShader, + + // NoCompositionModeFragmentShader must be first in the list: + NoCompositionModeFragmentShader, + MultiplyCompositionModeFragmentShader, + ScreenCompositionModeFragmentShader, + OverlayCompositionModeFragmentShader, + DarkenCompositionModeFragmentShader, + LightenCompositionModeFragmentShader, + ColorDodgeCompositionModeFragmentShader, + ColorBurnCompositionModeFragmentShader, + HardLightCompositionModeFragmentShader, + SoftLightCompositionModeFragmentShader, + DifferenceCompositionModeFragmentShader, + ExclusionCompositionModeFragmentShader, + + TotalSnippetCount, InvalidSnippetName + }; +#if defined (QT_DEBUG) + Q_ENUMS(SnippetName) + static QByteArray snippetNameStr(SnippetName snippetName); +#endif + +/* + // These allow the ShaderName enum to be used as a cache key + const int mainVertexOffset = 0; + const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader; + const int mainFragOffset = (1<<6) - MainFragmentShader_CMO; + const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader; + const int maskOffset = (1<<14) - NoMaskShader; + const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader; +*/ + + QOpenGLEngineSharedShaders(QOpenGLContext *context); + ~QOpenGLEngineSharedShaders(); + + QOpenGLShaderProgram *simpleProgram() { return simpleShaderProg; } + QOpenGLShaderProgram *blitProgram() { return blitShaderProg; } + // Compile the program if it's not already in the cache, return the item in the cache. + QOpenGLEngineShaderProg *findProgramInCache(const QOpenGLEngineShaderProg &prog); + // Compile the custom shader if it's not already in the cache, return the item in the cache. + + static QOpenGLEngineSharedShaders *shadersForContext(QOpenGLContext *context); + + // Ideally, this would be static and cleanup all programs in all contexts which + // contain the custom code. Currently it is just a hint and we rely on deleted + // custom shaders being cleaned up by being kicked out of the cache when it's + // full. + void cleanupCustomStage(QOpenGLCustomShaderStage* stage); + +private: + QOpenGLShaderProgram *blitShaderProg; + QOpenGLShaderProgram *simpleShaderProg; + QList cachedPrograms; + QList shaders; + + static const char* qShaderSnippets[TotalSnippetCount]; +}; + + +class QOpenGLEngineShaderProg +{ +public: + QOpenGLEngineShaderProg() : program(0) {} + + ~QOpenGLEngineShaderProg() { + if (program) + delete program; + } + + QOpenGLEngineSharedShaders::SnippetName mainVertexShader; + QOpenGLEngineSharedShaders::SnippetName positionVertexShader; + QOpenGLEngineSharedShaders::SnippetName mainFragShader; + QOpenGLEngineSharedShaders::SnippetName srcPixelFragShader; + QOpenGLEngineSharedShaders::SnippetName maskFragShader; + QOpenGLEngineSharedShaders::SnippetName compositionFragShader; + + QByteArray customStageSource; //TODO: Decent cache key for custom stages + QOpenGLShaderProgram* program; + + QVector uniformLocations; + + bool useTextureCoords; + bool useOpacityAttribute; + bool usePmvMatrixAttribute; + + bool operator==(const QOpenGLEngineShaderProg& other) { + // We don't care about the program + return ( mainVertexShader == other.mainVertexShader && + positionVertexShader == other.positionVertexShader && + mainFragShader == other.mainFragShader && + srcPixelFragShader == other.srcPixelFragShader && + maskFragShader == other.maskFragShader && + compositionFragShader == other.compositionFragShader && + customStageSource == other.customStageSource + ); + } +}; + +class Q_GUI_EXPORT QOpenGLEngineShaderManager : public QObject +{ + Q_OBJECT +public: + QOpenGLEngineShaderManager(QOpenGLContext* context); + ~QOpenGLEngineShaderManager(); + + enum MaskType {NoMask, PixelMask, SubPixelMaskPass1, SubPixelMaskPass2, SubPixelWithGammaMask}; + enum PixelSrcType { + ImageSrc = Qt::TexturePattern+1, + NonPremultipliedImageSrc = Qt::TexturePattern+2, + PatternSrc = Qt::TexturePattern+3, + TextureSrcWithPattern = Qt::TexturePattern+4 + }; + + enum Uniform { + ImageTexture, + PatternColor, + GlobalOpacity, + Depth, + MaskTexture, + FragmentColor, + LinearData, + Angle, + HalfViewportSize, + Fmp, + Fmp2MRadius2, + Inverse2Fmp2MRadius2, + SqrFr, + BRadius, + InvertedTextureSize, + BrushTransform, + BrushTexture, + Matrix, + NumUniforms + }; + + enum OpacityMode { + NoOpacity, + UniformOpacity, + AttributeOpacity + }; + + // There are optimizations we can do, depending on the brush transform: + // 1) May not have to apply perspective-correction + // 2) Can use lower precision for matrix + void optimiseForBrushTransform(QTransform::TransformationType transformType); + void setSrcPixelType(Qt::BrushStyle); + void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images + void setOpacityMode(OpacityMode); + void setMaskType(MaskType); + void setCompositionMode(QPainter::CompositionMode); + void setCustomStage(QOpenGLCustomShaderStage* stage); + void removeCustomStage(); + + GLuint getUniformLocation(Uniform id); + + void setDirty(); // someone has manually changed the current shader program + bool useCorrectShaderProg(); // returns true if the shader program needed to be changed + + void useSimpleProgram(); + void useBlitProgram(); + void setHasComplexGeometry(bool hasComplexGeometry) + { + complexGeometry = hasComplexGeometry; + shaderProgNeedsChanging = true; + } + bool hasComplexGeometry() const + { + return complexGeometry; + } + + QOpenGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen + QOpenGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers + QOpenGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer + + QOpenGLEngineSharedShaders* sharedShaders; + +private: + QOpenGLContext* ctx; + bool shaderProgNeedsChanging; + bool complexGeometry; + + // Current state variables which influence the choice of shader: + QTransform brushTransform; + int srcPixelType; + OpacityMode opacityMode; + MaskType maskType; + QPainter::CompositionMode compositionMode; + QOpenGLCustomShaderStage* customSrcStage; + + QOpenGLEngineShaderProg* currentShaderProg; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QOPENGLENGINE_SHADER_MANAGER_H diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h new file mode 100644 index 0000000000..cb85212308 --- /dev/null +++ b/src/gui/opengl/qopenglengineshadersource_p.h @@ -0,0 +1,529 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef QOPENGL_ENGINE_SHADER_SOURCE_H +#define QOPENGL_ENGINE_SHADER_SOURCE_H + +#include "qopenglengineshadermanager_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + + +static const char* const qopenglslMainVertexShader = "\n\ + void setPosition(); \n\ + void main(void) \n\ + { \n\ + setPosition(); \n\ + }\n"; + +static const char* const qopenglslMainWithTexCoordsVertexShader = "\n\ + attribute highp vec2 textureCoordArray; \n\ + varying highp vec2 textureCoords; \n\ + void setPosition(); \n\ + void main(void) \n\ + { \n\ + setPosition(); \n\ + textureCoords = textureCoordArray; \n\ + }\n"; + +static const char* const qopenglslMainWithTexCoordsAndOpacityVertexShader = "\n\ + attribute highp vec2 textureCoordArray; \n\ + attribute lowp float opacityArray; \n\ + varying highp vec2 textureCoords; \n\ + varying lowp float opacity; \n\ + void setPosition(); \n\ + void main(void) \n\ + { \n\ + setPosition(); \n\ + textureCoords = textureCoordArray; \n\ + opacity = opacityArray; \n\ + }\n"; + +// NOTE: We let GL do the perspective correction so texture lookups in the fragment +// shader are also perspective corrected. +static const char* const qopenglslPositionOnlyVertexShader = "\n\ + attribute highp vec2 vertexCoordsArray; \n\ + attribute highp vec3 pmvMatrix1; \n\ + attribute highp vec3 pmvMatrix2; \n\ + attribute highp vec3 pmvMatrix3; \n\ + void setPosition(void) \n\ + { \n\ + highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position = vec4(transformedPos.xy, 0.0, transformedPos.z); \n\ + }\n"; + +static const char* const qopenglslComplexGeometryPositionOnlyVertexShader = "\n\ + uniform highp mat3 matrix; \n\ + attribute highp vec2 vertexCoordsArray; \n\ + void setPosition(void) \n\ + { \n\ + gl_Position = vec4(matrix * vec3(vertexCoordsArray, 1), 1);\n\ + } \n"; + +static const char* const qopenglslUntransformedPositionVertexShader = "\n\ + attribute highp vec4 vertexCoordsArray; \n\ + void setPosition(void) \n\ + { \n\ + gl_Position = vertexCoordsArray; \n\ + }\n"; + +// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125 +static const char* const qopenglslPositionWithPatternBrushVertexShader = "\n\ + attribute highp vec2 vertexCoordsArray; \n\ + attribute highp vec3 pmvMatrix1; \n\ + attribute highp vec3 pmvMatrix2; \n\ + attribute highp vec3 pmvMatrix3; \n\ + uniform mediump vec2 halfViewportSize; \n\ + uniform highp vec2 invertedTextureSize; \n\ + uniform highp mat3 brushTransform; \n\ + varying highp vec2 patternTexCoords; \n\ + void setPosition(void) \n\ + { \n\ + highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1.0); \n\ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ + gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ + patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \n\ + }\n"; + +static const char* const qopenglslAffinePositionWithPatternBrushVertexShader + = qopenglslPositionWithPatternBrushVertexShader; + +static const char* const qopenglslPatternBrushSrcFragmentShader = "\n\ + uniform sampler2D brushTexture; \n\ + uniform lowp vec4 patternColor; \n\ + varying highp vec2 patternTexCoords;\n\ + lowp vec4 srcPixel() \n\ + { \n\ + return patternColor * (1.0 - texture2D(brushTexture, patternTexCoords).r); \n\ + }\n"; + + +// Linear Gradient Brush +static const char* const qopenglslPositionWithLinearGradientBrushVertexShader = "\n\ + attribute highp vec2 vertexCoordsArray; \n\ + attribute highp vec3 pmvMatrix1; \n\ + attribute highp vec3 pmvMatrix2; \n\ + attribute highp vec3 pmvMatrix3; \n\ + uniform mediump vec2 halfViewportSize; \n\ + uniform highp vec3 linearData; \n\ + uniform highp mat3 brushTransform; \n\ + varying mediump float index; \n\ + void setPosition() \n\ + { \n\ + highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ + gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ + index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \n\ + }\n"; + +static const char* const qopenglslAffinePositionWithLinearGradientBrushVertexShader + = qopenglslPositionWithLinearGradientBrushVertexShader; + +static const char* const qopenglslLinearGradientBrushSrcFragmentShader = "\n\ + uniform sampler2D brushTexture; \n\ + varying mediump float index; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + mediump vec2 val = vec2(index, 0.5); \n\ + return texture2D(brushTexture, val); \n\ + }\n"; + + +// Conical Gradient Brush +static const char* const qopenglslPositionWithConicalGradientBrushVertexShader = "\n\ + attribute highp vec2 vertexCoordsArray; \n\ + attribute highp vec3 pmvMatrix1; \n\ + attribute highp vec3 pmvMatrix2; \n\ + attribute highp vec3 pmvMatrix3; \n\ + uniform mediump vec2 halfViewportSize; \n\ + uniform highp mat3 brushTransform; \n\ + varying highp vec2 A; \n\ + void setPosition(void) \n\ + { \n\ + highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ + gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ + A = hTexCoords.xy * invertedHTexCoordsZ; \n\ + }\n"; + +static const char* const qopenglslAffinePositionWithConicalGradientBrushVertexShader + = qopenglslPositionWithConicalGradientBrushVertexShader; + +static const char* const qopenglslConicalGradientBrushSrcFragmentShader = "\n\ + #define INVERSE_2PI 0.1591549430918953358 \n\ + uniform sampler2D brushTexture; \n\ + uniform mediump float angle; \n\ + varying highp vec2 A; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + highp float t; \n\ + if (abs(A.y) == abs(A.x)) \n\ + t = (atan(-A.y + 0.002, A.x) + angle) * INVERSE_2PI; \n\ + else \n\ + t = (atan(-A.y, A.x) + angle) * INVERSE_2PI; \n\ + return texture2D(brushTexture, vec2(t - floor(t), 0.5)); \n\ + }\n"; + + +// Radial Gradient Brush +static const char* const qopenglslPositionWithRadialGradientBrushVertexShader = "\n\ + attribute highp vec2 vertexCoordsArray;\n\ + attribute highp vec3 pmvMatrix1; \n\ + attribute highp vec3 pmvMatrix2; \n\ + attribute highp vec3 pmvMatrix3; \n\ + uniform mediump vec2 halfViewportSize; \n\ + uniform highp mat3 brushTransform; \n\ + uniform highp vec2 fmp; \n\ + uniform highp vec3 bradius; \n\ + varying highp float b; \n\ + varying highp vec2 A; \n\ + void setPosition(void) \n\ + {\n\ + highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ + gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ + A = hTexCoords.xy * invertedHTexCoordsZ; \n\ + b = bradius.x + 2.0 * dot(A, fmp); \n\ + }\n"; + +static const char* const qopenglslAffinePositionWithRadialGradientBrushVertexShader + = qopenglslPositionWithRadialGradientBrushVertexShader; + +static const char* const qopenglslRadialGradientBrushSrcFragmentShader = "\n\ + uniform sampler2D brushTexture; \n\ + uniform highp float fmp2_m_radius2; \n\ + uniform highp float inverse_2_fmp2_m_radius2; \n\ + uniform highp float sqrfr; \n\ + varying highp float b; \n\ + varying highp vec2 A; \n\ + uniform highp vec3 bradius; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + highp float c = sqrfr-dot(A, A); \n\ + highp float det = b*b - 4.0*fmp2_m_radius2*c; \n\ + lowp vec4 result = vec4(0.0); \n\ + if (det >= 0.0) { \n\ + highp float detSqrt = sqrt(det); \n\ + highp float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); \n\ + if (bradius.y + w * bradius.z >= 0.0) \n\ + result = texture2D(brushTexture, vec2(w, 0.5)); \n\ + } \n\ + return result; \n\ + }\n"; + + +// Texture Brush +static const char* const qopenglslPositionWithTextureBrushVertexShader = "\n\ + attribute highp vec2 vertexCoordsArray; \n\ + attribute highp vec3 pmvMatrix1; \n\ + attribute highp vec3 pmvMatrix2; \n\ + attribute highp vec3 pmvMatrix3; \n\ + uniform mediump vec2 halfViewportSize; \n\ + uniform highp vec2 invertedTextureSize; \n\ + uniform highp mat3 brushTransform; \n\ + varying highp vec2 brushTextureCoords; \n\ + void setPosition(void) \n\ + { \n\ + highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ + vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ + gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ + mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ + mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ + mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ + gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ + brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \n\ + }\n"; + +static const char* const qopenglslAffinePositionWithTextureBrushVertexShader + = qopenglslPositionWithTextureBrushVertexShader; + +#if defined(QT_OPENGL_ES_2) +// OpenGL ES does not support GL_REPEAT wrap modes for NPOT textures. So instead, +// we emulate GL_REPEAT by only taking the fractional part of the texture coords. +// TODO: Special case POT textures which don't need this emulation +static const char* const qopenglslTextureBrushSrcFragmentShader = "\n\ + varying highp vec2 brushTextureCoords; \n\ + uniform sampler2D brushTexture; \n\ + lowp vec4 srcPixel() { \n\ + return texture2D(brushTexture, fract(brushTextureCoords)); \n\ + }\n"; +#else +static const char* const qopenglslTextureBrushSrcFragmentShader = "\n\ + varying highp vec2 brushTextureCoords; \n\ + uniform sampler2D brushTexture; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + return texture2D(brushTexture, brushTextureCoords); \n\ + }\n"; +#endif + +static const char* const qopenglslTextureBrushSrcWithPatternFragmentShader = "\n\ + varying highp vec2 brushTextureCoords; \n\ + uniform lowp vec4 patternColor; \n\ + uniform sampler2D brushTexture; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + return patternColor * (1.0 - texture2D(brushTexture, brushTextureCoords).r); \n\ + }\n"; + +// Solid Fill Brush +static const char* const qopenglslSolidBrushSrcFragmentShader = "\n\ + uniform lowp vec4 fragmentColor; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + return fragmentColor; \n\ + }\n"; + +static const char* const qopenglslImageSrcFragmentShader = "\n\ + varying highp vec2 textureCoords; \n\ + uniform sampler2D imageTexture; \n\ + lowp vec4 srcPixel() \n\ + { \n" + "return texture2D(imageTexture, textureCoords); \n" + "}\n"; + +static const char* const qopenglslCustomSrcFragmentShader = "\n\ + varying highp vec2 textureCoords; \n\ + uniform sampler2D imageTexture; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + return customShader(imageTexture, textureCoords); \n\ + }\n"; + +static const char* const qopenglslImageSrcWithPatternFragmentShader = "\n\ + varying highp vec2 textureCoords; \n\ + uniform lowp vec4 patternColor; \n\ + uniform sampler2D imageTexture; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + return patternColor * (1.0 - texture2D(imageTexture, textureCoords).r); \n\ + }\n"; + +static const char* const qopenglslNonPremultipliedImageSrcFragmentShader = "\n\ + varying highp vec2 textureCoords; \n\ + uniform sampler2D imageTexture; \n\ + lowp vec4 srcPixel() \n\ + { \n\ + lowp vec4 sample = texture2D(imageTexture, textureCoords); \n\ + sample.rgb = sample.rgb * sample.a; \n\ + return sample; \n\ + }\n"; + +static const char* const qopenglslShockingPinkSrcFragmentShader = "\n\ + lowp vec4 srcPixel() \n\ + { \n\ + return vec4(0.98, 0.06, 0.75, 1.0); \n\ + }\n"; + +static const char* const qopenglslMainFragmentShader_ImageArrays = "\n\ + varying lowp float opacity; \n\ + lowp vec4 srcPixel(); \n\ + void main() \n\ + { \n\ + gl_FragColor = srcPixel() * opacity; \n\ + }\n"; + +static const char* const qopenglslMainFragmentShader_CMO = "\n\ + uniform lowp float globalOpacity; \n\ + lowp vec4 srcPixel(); \n\ + lowp vec4 applyMask(lowp vec4); \n\ + lowp vec4 compose(lowp vec4); \n\ + void main() \n\ + { \n\ + gl_FragColor = applyMask(compose(srcPixel()*globalOpacity))); \n\ + }\n"; + +static const char* const qopenglslMainFragmentShader_CM = "\n\ + lowp vec4 srcPixel(); \n\ + lowp vec4 applyMask(lowp vec4); \n\ + lowp vec4 compose(lowp vec4); \n\ + void main() \n\ + { \n\ + gl_FragColor = applyMask(compose(srcPixel())); \n\ + }\n"; + +static const char* const qopenglslMainFragmentShader_MO = "\n\ + uniform lowp float globalOpacity; \n\ + lowp vec4 srcPixel(); \n\ + lowp vec4 applyMask(lowp vec4); \n\ + void main() \n\ + { \n\ + gl_FragColor = applyMask(srcPixel()*globalOpacity); \n\ + }\n"; + +static const char* const qopenglslMainFragmentShader_M = "\n\ + lowp vec4 srcPixel(); \n\ + lowp vec4 applyMask(lowp vec4); \n\ + void main() \n\ + { \n\ + gl_FragColor = applyMask(srcPixel()); \n\ + }\n"; + +static const char* const qopenglslMainFragmentShader_CO = "\n\ + uniform lowp float globalOpacity; \n\ + lowp vec4 srcPixel(); \n\ + lowp vec4 compose(lowp vec4); \n\ + void main() \n\ + { \n\ + gl_FragColor = compose(srcPixel()*globalOpacity); \n\ + }\n"; + +static const char* const qopenglslMainFragmentShader_C = "\n\ + lowp vec4 srcPixel(); \n\ + lowp vec4 compose(lowp vec4); \n\ + void main() \n\ + { \n\ + gl_FragColor = compose(srcPixel()); \n\ + }\n"; + +static const char* const qopenglslMainFragmentShader_O = "\n\ + uniform lowp float globalOpacity; \n\ + lowp vec4 srcPixel(); \n\ + void main() \n\ + { \n\ + gl_FragColor = srcPixel()*globalOpacity; \n\ + }\n"; + +static const char* const qopenglslMainFragmentShader = "\n\ + lowp vec4 srcPixel(); \n\ + void main() \n\ + { \n\ + gl_FragColor = srcPixel(); \n\ + }\n"; + +static const char* const qopenglslMaskFragmentShader = "\n\ + varying highp vec2 textureCoords;\n\ + uniform sampler2D maskTexture;\n\ + lowp vec4 applyMask(lowp vec4 src) \n\ + {\n\ + lowp vec4 mask = texture2D(maskTexture, textureCoords); \n\ + return src * mask.a; \n\ + }\n"; + +// For source over with subpixel antialiasing, the final color is calculated per component as follows +// (.a is alpha component, .c is red, green or blue component): +// alpha = src.a * mask.c * opacity +// dest.c = dest.c * (1 - alpha) + src.c * alpha +// +// In the first pass, calculate: dest.c = dest.c * (1 - alpha) with blend funcs: zero, 1 - source color +// In the second pass, calculate: dest.c = dest.c + src.c * alpha with blend funcs: one, one +// +// If source is a solid color (src is constant), only the first pass is needed, with blend funcs: constant, 1 - source color + +// For source composition with subpixel antialiasing, the final color is calculated per component as follows: +// alpha = src.a * mask.c * opacity +// dest.c = dest.c * (1 - mask.c) + src.c * alpha +// + +static const char* const qopenglslRgbMaskFragmentShaderPass1 = "\n\ + varying highp vec2 textureCoords;\n\ + uniform sampler2D maskTexture;\n\ + lowp vec4 applyMask(lowp vec4 src) \n\ + { \n\ + lowp vec4 mask = texture2D(maskTexture, textureCoords); \n\ + return src.a * mask; \n\ + }\n"; + +static const char* const qopenglslRgbMaskFragmentShaderPass2 = "\n\ + varying highp vec2 textureCoords;\n\ + uniform sampler2D maskTexture;\n\ + lowp vec4 applyMask(lowp vec4 src) \n\ + { \n\ + lowp vec4 mask = texture2D(maskTexture, textureCoords); \n\ + return src * mask; \n\ + }\n"; + +/* + Left to implement: + RgbMaskFragmentShader, + RgbMaskWithGammaFragmentShader, + + MultiplyCompositionModeFragmentShader, + ScreenCompositionModeFragmentShader, + OverlayCompositionModeFragmentShader, + DarkenCompositionModeFragmentShader, + LightenCompositionModeFragmentShader, + ColorDodgeCompositionModeFragmentShader, + ColorBurnCompositionModeFragmentShader, + HardLightCompositionModeFragmentShader, + SoftLightCompositionModeFragmentShader, + DifferenceCompositionModeFragmentShader, + ExclusionCompositionModeFragmentShader, +*/ + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // GLGC_SHADER_SOURCE_H diff --git a/src/gui/opengl/qopenglextensions_p.h b/src/gui/opengl/qopenglextensions_p.h new file mode 100644 index 0000000000..a4d88a059e --- /dev/null +++ b/src/gui/opengl/qopenglextensions_p.h @@ -0,0 +1,676 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGL_EXTENSIONS_P_H +#define QOPENGL_EXTENSIONS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the Qt OpenGL classes. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qopenglfunctions.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#if 0 +#ifndef GL_ARB_vertex_buffer_object +typedef ptrdiff_t GLintptrARB; +typedef ptrdiff_t GLsizeiptrARB; +#endif +#endif + +#ifndef GL_VERSION_2_0 +typedef char GLchar; +#endif + +struct QOpenGLExtensionsPrivate; + +class Q_GUI_EXPORT QOpenGLExtensions : public QOpenGLFunctions +{ + Q_DECLARE_PRIVATE(QOpenGLExtensions) +public: + QOpenGLExtensions(); + QOpenGLExtensions(QOpenGLContext *context); + ~QOpenGLExtensions() {} + + enum OpenGLExtension { + TextureRectangle = 0x00000001, + GenerateMipmap = 0x00000002, + TextureCompression = 0x00000004, + MirroredRepeat = 0x00000008, + FramebufferMultisample = 0x00000010, + StencilTwoSide = 0x00000020, + StencilWrap = 0x00000040, + PackedDepthStencil = 0x00000080, + NVFloatBuffer = 0x00000100, + PixelBufferObject = 0x00000200, + FramebufferBlit = 0x00000400, + BGRATextureFormat = 0x00000800, + DDSTextureCompression = 0x00001000, + ETC1TextureCompression = 0x00002000, + PVRTCTextureCompression = 0x00004000, + ElementIndexUint = 0x00008000, + Depth24 = 0x00010000, + SRGBFrameBuffer = 0x00020000, + MapBuffer = 0x00040000, + GeometryShaders = 0x00080000 + }; + Q_DECLARE_FLAGS(OpenGLExtensions, OpenGLExtension) + + OpenGLExtensions openGLExtensions(); + bool hasOpenGLExtension(QOpenGLExtensions::OpenGLExtension extension) const; + + void initializeGLExtensions(); + + GLvoid *glMapBuffer(GLenum target, GLenum access); + GLboolean glUnmapBuffer(GLenum target); + + void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter); + + void glRenderbufferStorageMultisample(GLenum target, GLsizei samples, + GLenum internalFormat, + GLsizei width, GLsizei height); + + void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); + +private: + static bool isInitialized(const QOpenGLFunctionsPrivate *d) { return d != 0; } +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLExtensions::OpenGLExtensions) + +struct QOpenGLExtensionsPrivate : public QOpenGLFunctionsPrivate +{ + QOpenGLExtensionsPrivate(QOpenGLContext *ctx); + + GLvoid* (QOPENGLF_APIENTRYP MapBuffer)(GLenum target, GLenum access); + GLboolean (QOPENGLF_APIENTRYP UnmapBuffer)(GLenum target); + void (QOPENGLF_APIENTRYP BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter); + void (QOPENGLF_APIENTRYP RenderbufferStorageMultisample)(GLenum target, GLsizei samples, + GLenum internalFormat, + GLsizei width, GLsizei height); + void (QOPENGLF_APIENTRYP GetBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +}; + +inline GLvoid *QOpenGLExtensions::glMapBuffer(GLenum target, GLenum access) +{ + Q_D(QOpenGLExtensions); + Q_ASSERT(QOpenGLExtensions::isInitialized(d)); + GLvoid *result = d->MapBuffer(target, access); + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline GLboolean QOpenGLExtensions::glUnmapBuffer(GLenum target) +{ + Q_D(QOpenGLExtensions); + Q_ASSERT(QOpenGLExtensions::isInitialized(d)); + GLboolean result = d->UnmapBuffer(target); + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline void QOpenGLExtensions::glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + Q_D(QOpenGLExtensions); + Q_ASSERT(QOpenGLExtensions::isInitialized(d)); + d->BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLExtensions::glRenderbufferStorageMultisample(GLenum target, GLsizei samples, + GLenum internalFormat, + GLsizei width, GLsizei height) +{ + Q_D(QOpenGLExtensions); + Q_ASSERT(QOpenGLExtensions::isInitialized(d)); + d->RenderbufferStorageMultisample(target, samples, internalFormat, width, height); + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLExtensions::glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) +{ + Q_D(QOpenGLExtensions); + Q_ASSERT(QOpenGLExtensions::isInitialized(d)); + d->GetBufferSubData(target, offset, size, data); + Q_OPENGL_FUNCTIONS_DEBUG +} + +#ifndef GL_FRAMEBUFFER_SRGB_CAPABLE +#define GL_FRAMEBUFFER_SRGB_CAPABLE 0x8DBA +#endif +#ifndef GL_FRAMEBUFFER_SRGB +#define GL_FRAMEBUFFER_SRGB 0x8DB9 +#endif +#ifndef GL_ARRAY_BUFFER +#define GL_ARRAY_BUFFER 0x8892 +#endif +#ifndef GL_STATIC_DRAW +#define GL_STATIC_DRAW 0x88E4 +#endif +#ifndef GL_TEXTURE_RECTANGLE +#define GL_TEXTURE_RECTANGLE 0x84F5 +#endif +#ifndef GL_TEXTURE_BINDING_RECTANGLE +#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 +#endif +#ifndef GL_PROXY_TEXTURE_RECTANGLE +#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 +#endif +#ifndef GL_MAX_RECTANGLE_TEXTURE_SIZE +#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 +#endif +#ifndef GL_BGRA +#define GL_BGRA 0x80E1 +#endif +#ifndef GL_RGB16 +#define GL_RGB16 0x8054 +#endif +#ifndef GL_UNSIGNED_SHORT_5_6_5 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#endif +#ifndef GL_UNSIGNED_INT_8_8_8_8_REV +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#endif +#ifndef GL_MULTISAMPLE +#define GL_MULTISAMPLE 0x809D +#endif +#ifndef GL_CLAMP_TO_EDGE +#define GL_CLAMP_TO_EDGE 0x812F +#endif +#ifndef GL_MIRRORED_REPEAT +#define GL_MIRRORED_REPEAT 0x8370 +#endif +#ifndef GL_GENERATE_MIPMAP +#define GL_GENERATE_MIPMAP 0x8191 +#endif +#ifndef GL_GENERATE_MIPMAP_HINT +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#endif +#ifndef GL_FRAGMENT_PROGRAM +#define GL_FRAGMENT_PROGRAM 0x8804 +#endif +#ifndef GL_PROGRAM_FORMAT_ASCII +#define GL_PROGRAM_FORMAT_ASCII 0x8875 +#endif +#ifndef GL_PIXEL_UNPACK_BUFFER +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#endif +#ifndef GL_WRITE_ONLY +#define GL_WRITE_ONLY 0x88B9 +#endif +#ifndef GL_STREAM_DRAW +#define GL_STREAM_DRAW 0x88E0 +#endif +#ifndef GL_STENCIL_TEST_TWO_SIDE +#define GL_STENCIL_TEST_TWO_SIDE 0x8910 +#endif +#ifndef GL_INCR_WRAP +#define GL_INCR_WRAP 0x8507 +#endif +#ifndef GL_DECR_WRAP +#define GL_DECR_WRAP 0x8508 +#endif +#ifndef GL_TEXTURE0 +#define GL_TEXTURE0 0x84C0 +#endif +#ifndef GL_TEXTURE1 +#define GL_TEXTURE1 0x84C1 +#endif +#ifndef GL_DEPTH_COMPONENT16 +#define GL_DEPTH_COMPONENT16 0x81A5 +#endif +#ifndef GL_DEPTH_COMPONENT24 +#define GL_DEPTH_COMPONENT24 0x81A6 +#endif +#ifndef GL_INVALID_FRAMEBUFFER_OPERATION +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#endif +#ifndef GL_MAX_RENDERBUFFER_SIZE +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#endif +#ifndef GL_FRAMEBUFFER_BINDING +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#endif +#ifndef GL_RENDERBUFFER_BINDING +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET 0x8CD4 +#endif +#ifndef GL_FRAMEBUFFER_COMPLETE +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT +#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT 0x8CD8 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_FORMATS +#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS 0x8CDA +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER +#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER +#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC +#endif +#ifndef GL_FRAMEBUFFER_UNSUPPORTED +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#endif +#ifndef GL_MAX_COLOR_ATTACHMENTS +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#endif +#ifndef GL_COLOR_ATTACHMENT0 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#endif +#ifndef GL_COLOR_ATTACHMENT1 +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#endif +#ifndef GL_COLOR_ATTACHMENT2 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#endif +#ifndef GL_COLOR_ATTACHMENT3 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#endif +#ifndef GL_COLOR_ATTACHMENT4 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#endif +#ifndef GL_COLOR_ATTACHMENT5 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#endif +#ifndef GL_COLOR_ATTACHMENT6 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#endif +#ifndef GL_COLOR_ATTACHMENT7 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#endif +#ifndef GL_COLOR_ATTACHMENT8 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#endif +#ifndef GL_COLOR_ATTACHMENT9 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#endif +#ifndef GL_COLOR_ATTACHMENT10 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#endif +#ifndef GL_COLOR_ATTACHMENT11 +#define GL_COLOR_ATTACHMENT11 0x8CEB +#endif +#ifndef GL_COLOR_ATTACHMENT12 +#define GL_COLOR_ATTACHMENT12 0x8CEC +#endif +#ifndef GL_COLOR_ATTACHMENT13 +#define GL_COLOR_ATTACHMENT13 0x8CED +#endif +#ifndef GL_COLOR_ATTACHMENT14 +#define GL_COLOR_ATTACHMENT14 0x8CEE +#endif +#ifndef GL_COLOR_ATTACHMENT15 +#define GL_COLOR_ATTACHMENT15 0x8CEF +#endif +#ifndef GL_DEPTH_ATTACHMENT +#define GL_DEPTH_ATTACHMENT 0x8D00 +#endif +#ifndef GL_STENCIL_ATTACHMENT +#define GL_STENCIL_ATTACHMENT 0x8D20 +#endif +#ifndef GL_FRAMEBUFFER +#define GL_FRAMEBUFFER 0x8D40 +#endif +#ifndef GL_RENDERBUFFER +#define GL_RENDERBUFFER 0x8D41 +#endif +#ifndef GL_RENDERBUFFER_WIDTH +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#endif +#ifndef GL_RENDERBUFFER_HEIGHT +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#endif +#ifndef GL_RENDERBUFFER_INTERNAL_FORMAT +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#endif +#ifndef GL_STENCIL_INDEX +#define GL_STENCIL_INDEX 0x8D45 +#endif +#ifndef GL_STENCIL_INDEX1 +#define GL_STENCIL_INDEX1 0x8D46 +#endif +#ifndef GL_STENCIL_INDEX4 +#define GL_STENCIL_INDEX4 0x8D47 +#endif +#ifndef GL_STENCIL_INDEX8 +#define GL_STENCIL_INDEX8 0x8D48 +#endif +#ifndef GL_STENCIL_INDEX16 +#define GL_STENCIL_INDEX16 0x8D49 +#endif +#ifndef GL_RENDERBUFFER_RED_SIZE +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#endif +#ifndef GL_RENDERBUFFER_GREEN_SIZE +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#endif +#ifndef GL_RENDERBUFFER_BLUE_SIZE +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#endif +#ifndef GL_RENDERBUFFER_ALPHA_SIZE +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#endif +#ifndef GL_RENDERBUFFER_DEPTH_SIZE +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#endif +#ifndef GL_RENDERBUFFER_STENCIL_SIZE +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#endif +#ifndef GL_READ_FRAMEBUFFER +#define GL_READ_FRAMEBUFFER 0x8CA8 +#endif +#ifndef GL_RENDERBUFFER_SAMPLES +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 +#endif +#ifndef GL_MAX_SAMPLES +#define GL_MAX_SAMPLES 0x8D57 +#endif +#ifndef GL_DRAW_FRAMEBUFFER +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#endif +#ifndef GL_DEPTH_STENCIL +#define GL_DEPTH_STENCIL 0x84F9 +#endif +#ifndef GL_UNSIGNED_INT_24_8 +#define GL_UNSIGNED_INT_24_8 0x84FA +#endif +#ifndef GL_DEPTH24_STENCIL8 +#define GL_DEPTH24_STENCIL8 0x88F0 +#endif +#ifndef GL_TEXTURE_STENCIL_SIZE +#define GL_TEXTURE_STENCIL_SIZE 0x88F1 +#endif +#ifndef GL_CLAMP_TO_EDGE +#define GL_CLAMP_TO_EDGE 0x812F +#endif +#ifndef GL_PACK_SKIP_IMAGES +#define GL_PACK_SKIP_IMAGES 0x806B +#endif +#ifndef GL_PACK_IMAGE_HEIGHT +#define GL_PACK_IMAGE_HEIGHT 0x806C +#endif +#ifndef GL_UNPACK_SKIP_IMAGES +#define GL_UNPACK_SKIP_IMAGES 0x806D +#endif +#ifndef GL_UNPACK_IMAGE_HEIGHT +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#endif +#ifndef GL_CONSTANT_COLOR +#define GL_CONSTANT_COLOR 0x8001 +#endif +#ifndef GL_ONE_MINUS_CONSTANT_COLOR +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#endif +#ifndef GL_CONSTANT_ALPHA +#define GL_CONSTANT_ALPHA 0x8003 +#endif +#ifndef GL_ONE_MINUS_CONSTANT_ALPHA +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#endif +#ifndef GL_INCR_WRAP +#define GL_INCR_WRAP 0x8507 +#endif +#ifndef GL_DECR_WRAP +#define GL_DECR_WRAP 0x8508 +#endif +#ifndef GL_ARRAY_BUFFER +#define GL_ARRAY_BUFFER 0x8892 +#endif +#ifndef GL_ELEMENT_ARRAY_BUFFER +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#endif +#ifndef GL_STREAM_DRAW +#define GL_STREAM_DRAW 0x88E0 +#endif +#ifndef GL_STREAM_READ +#define GL_STREAM_READ 0x88E1 +#endif +#ifndef GL_STREAM_COPY +#define GL_STREAM_COPY 0x88E2 +#endif +#ifndef GL_STATIC_DRAW +#define GL_STATIC_DRAW 0x88E4 +#endif +#ifndef GL_STATIC_READ +#define GL_STATIC_READ 0x88E5 +#endif +#ifndef GL_STATIC_COPY +#define GL_STATIC_COPY 0x88E6 +#endif +#ifndef GL_DYNAMIC_DRAW +#define GL_DYNAMIC_DRAW 0x88E8 +#endif +#ifndef GL_DYNAMIC_READ +#define GL_DYNAMIC_READ 0x88E9 +#endif +#ifndef GL_DYNAMIC_COPY +#define GL_DYNAMIC_COPY 0x88EA +#endif +#ifndef GL_FRAGMENT_SHADER +#define GL_FRAGMENT_SHADER 0x8B30 +#endif +#ifndef GL_VERTEX_SHADER +#define GL_VERTEX_SHADER 0x8B31 +#endif +#ifndef GL_FLOAT_VEC2 +#define GL_FLOAT_VEC2 0x8B50 +#endif +#ifndef GL_FLOAT_VEC3 +#define GL_FLOAT_VEC3 0x8B51 +#endif +#ifndef GL_FLOAT_VEC4 +#define GL_FLOAT_VEC4 0x8B52 +#endif +#ifndef GL_INT_VEC2 +#define GL_INT_VEC2 0x8B53 +#endif +#ifndef GL_INT_VEC3 +#define GL_INT_VEC3 0x8B54 +#endif +#ifndef GL_INT_VEC4 +#define GL_INT_VEC4 0x8B55 +#endif +#ifndef GL_BOOL +#define GL_BOOL 0x8B56 +#endif +#ifndef GL_BOOL_VEC2 +#define GL_BOOL_VEC2 0x8B57 +#endif +#ifndef GL_BOOL_VEC3 +#define GL_BOOL_VEC3 0x8B58 +#endif +#ifndef GL_BOOL_VEC4 +#define GL_BOOL_VEC4 0x8B59 +#endif +#ifndef GL_FLOAT_MAT2 +#define GL_FLOAT_MAT2 0x8B5A +#endif +#ifndef GL_FLOAT_MAT3 +#define GL_FLOAT_MAT3 0x8B5B +#endif +#ifndef GL_FLOAT_MAT4 +#define GL_FLOAT_MAT4 0x8B5C +#endif +#ifndef GL_SAMPLER_1D +#define GL_SAMPLER_1D 0x8B5D +#endif +#ifndef GL_SAMPLER_2D +#define GL_SAMPLER_2D 0x8B5E +#endif +#ifndef GL_SAMPLER_3D +#define GL_SAMPLER_3D 0x8B5F +#endif +#ifndef GL_SAMPLER_CUBE +#define GL_SAMPLER_CUBE 0x8B60 +#endif +#ifndef GL_COMPILE_STATUS +#define GL_COMPILE_STATUS 0x8B81 +#endif +#ifndef GL_LINK_STATUS +#define GL_LINK_STATUS 0x8B82 +#endif +#ifndef GL_INFO_LOG_LENGTH +#define GL_INFO_LOG_LENGTH 0x8B84 +#endif +#ifndef GL_ACTIVE_UNIFORMS +#define GL_ACTIVE_UNIFORMS 0x8B86 +#endif +#ifndef GL_ACTIVE_UNIFORM_MAX_LENGTH +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#endif +#ifndef GL_ACTIVE_ATTRIBUTES +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#endif +#ifndef GL_ACTIVE_ATTRIBUTE_MAX_LENGTH +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#endif +#ifndef GL_GEOMETRY_SHADER +#define GL_GEOMETRY_SHADER 0x8DD9 +#endif +#ifndef GL_GEOMETRY_VERTICES_OUT +#define GL_GEOMETRY_VERTICES_OUT 0x8DDA +#endif +#ifndef GL_GEOMETRY_INPUT_TYPE +#define GL_GEOMETRY_INPUT_TYPE 0x8DDB +#endif +#ifndef GL_GEOMETRY_OUTPUT_TYPE +#define GL_GEOMETRY_OUTPUT_TYPE 0x8DDC +#endif +#ifndef GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 +#endif +#ifndef GL_MAX_GEOMETRY_VARYING_COMPONENTS +#define GL_MAX_GEOMETRY_VARYING_COMPONENTS 0x8DDD +#endif +#ifndef GL_MAX_VERTEX_VARYING_COMPONENTS +#define GL_MAX_VERTEX_VARYING_COMPONENTS 0x8DDE +#endif +#ifndef GL_MAX_VARYING_COMPONENTS +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#endif +#ifndef GL_MAX_GEOMETRY_UNIFORM_COMPONENTS +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF +#endif +#ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#endif +#ifndef GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#endif +#ifndef GL_LINES_ADJACENCY +#define GL_LINES_ADJACENCY 0xA +#endif +#ifndef GL_LINE_STRIP_ADJACENCY +#define GL_LINE_STRIP_ADJACENCY 0xB +#endif +#ifndef GL_TRIANGLES_ADJACENCY +#define GL_TRIANGLES_ADJACENCY 0xC +#endif +#ifndef GL_TRIANGLE_STRIP_ADJACENCY +#define GL_TRIANGLE_STRIP_ADJACENCY 0xD +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT 0x8DA9 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_LAYERED +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#endif +#ifndef GL_PROGRAM_POINT_SIZE +#define GL_PROGRAM_POINT_SIZE 0x8642 +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QOPENGL_EXTENSIONS_P_H diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp new file mode 100644 index 0000000000..543a48fc08 --- /dev/null +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -0,0 +1,1354 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenglframebufferobject.h" +#include "qopenglframebufferobject_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#define QOPENGL_FUNC_CONTEXT QOpenGLContext *ctx = QOpenGLContext::currentContext(); +#define QOPENGL_FUNCP_CONTEXT QOpenGLContext *ctx = QOpenGLContext::currentContext(); + +#ifndef QT_NO_DEBUG +#define QT_RESET_GLERROR() \ +{ \ + while (glGetError() != GL_NO_ERROR) {} \ +} +#define QT_CHECK_GLERROR() \ +{ \ + GLenum err = glGetError(); \ + if (err != GL_NO_ERROR) { \ + qDebug("[%s line %d] GL Error: %d", \ + __FILE__, __LINE__, (int)err); \ + } \ +} +#else +#define QT_RESET_GLERROR() {} +#define QT_CHECK_GLERROR() {} +#endif + +/*! + \class QOpenGLFramebufferObjectFormat + \brief The QOpenGLFramebufferObjectFormat class specifies the format of an OpenGL + framebuffer object. + + \since 4.6 + + \ingroup painting-3D + + A framebuffer object has several characteristics: + \list + \i \link setSamples() Number of samples per pixels.\endlink + \i \link setAttachment() Depth and/or stencil attachments.\endlink + \i \link setTextureTarget() Texture target.\endlink + \i \link setInternalTextureFormat() Internal texture format.\endlink + \endlist + + Note that the desired attachments or number of samples per pixels might not + be supported by the hardware driver. Call QOpenGLFramebufferObject::format() + after creating a QOpenGLFramebufferObject to find the exact format that was + used to create the frame buffer object. + + \sa QOpenGLFramebufferObject +*/ + +/*! + \internal +*/ +void QOpenGLFramebufferObjectFormat::detach() +{ + if (d->ref != 1) { + QOpenGLFramebufferObjectFormatPrivate *newd + = new QOpenGLFramebufferObjectFormatPrivate(d); + if (!d->ref.deref()) + delete d; + d = newd; + } +} + +/*! + Creates a QOpenGLFramebufferObjectFormat object for specifying + the format of an OpenGL framebuffer object. + + By default the format specifies a non-multisample framebuffer object with no + attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8. + On OpenGL/ES systems, the default internal format is \c GL_RGBA. + + \sa samples(), attachment(), internalTextureFormat() +*/ + +QOpenGLFramebufferObjectFormat::QOpenGLFramebufferObjectFormat() +{ + d = new QOpenGLFramebufferObjectFormatPrivate; +} + +/*! + Constructs a copy of \a other. +*/ + +QOpenGLFramebufferObjectFormat::QOpenGLFramebufferObjectFormat(const QOpenGLFramebufferObjectFormat &other) +{ + d = other.d; + d->ref.ref(); +} + +/*! + Assigns \a other to this object. +*/ + +QOpenGLFramebufferObjectFormat &QOpenGLFramebufferObjectFormat::operator=(const QOpenGLFramebufferObjectFormat &other) +{ + if (d != other.d) { + other.d->ref.ref(); + if (!d->ref.deref()) + delete d; + d = other.d; + } + return *this; +} + +/*! + Destroys the QOpenGLFramebufferObjectFormat. +*/ +QOpenGLFramebufferObjectFormat::~QOpenGLFramebufferObjectFormat() +{ + if (!d->ref.deref()) + delete d; +} + +/*! + Sets the number of samples per pixel for a multisample framebuffer object + to \a samples. The default sample count of 0 represents a regular + non-multisample framebuffer object. + + If the desired amount of samples per pixel is not supported by the hardware + then the maximum number of samples per pixel will be used. Note that + multisample framebuffer objects can not be bound as textures. Also, the + \c{GL_EXT_framebuffer_multisample} extension is required to create a + framebuffer with more than one sample per pixel. + + \sa samples() +*/ +void QOpenGLFramebufferObjectFormat::setSamples(int samples) +{ + detach(); + d->samples = samples; +} + +/*! + Returns the number of samples per pixel if a framebuffer object + is a multisample framebuffer object. Otherwise, returns 0. + The default value is 0. + + \sa setSamples() +*/ +int QOpenGLFramebufferObjectFormat::samples() const +{ + return d->samples; +} + +/*! + \since 4.8 + + Enables mipmapping if \a enabled is true; otherwise disables it. + + Mipmapping is disabled by default. + + If mipmapping is enabled, additional memory will be allocated for + the mipmap levels. The mipmap levels can be updated by binding the + texture and calling glGenerateMipmap(). Mipmapping cannot be enabled + for multisampled framebuffer objects. + + \sa mipmap(), QOpenGLFramebufferObject::texture() +*/ +void QOpenGLFramebufferObjectFormat::setMipmap(bool enabled) +{ + detach(); + d->mipmap = enabled; +} + +/*! + \since 4.8 + + Returns true if mipmapping is enabled. + + \sa setMipmap() +*/ +bool QOpenGLFramebufferObjectFormat::mipmap() const +{ + return d->mipmap; +} + +/*! + Sets the attachment configuration of a framebuffer object to \a attachment. + + \sa attachment() +*/ +void QOpenGLFramebufferObjectFormat::setAttachment(QOpenGLFramebufferObject::Attachment attachment) +{ + detach(); + d->attachment = attachment; +} + +/*! + Returns the configuration of the depth and stencil buffers attached to + a framebuffer object. The default is QOpenGLFramebufferObject::NoAttachment. + + \sa setAttachment() +*/ +QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObjectFormat::attachment() const +{ + return d->attachment; +} + +/*! + Sets the texture target of the texture attached to a framebuffer object to + \a target. Ignored for multisample framebuffer objects. + + \sa textureTarget(), samples() +*/ +void QOpenGLFramebufferObjectFormat::setTextureTarget(GLenum target) +{ + detach(); + d->target = target; +} + +/*! + Returns the texture target of the texture attached to a framebuffer object. + Ignored for multisample framebuffer objects. The default is + \c GL_TEXTURE_2D. + + \sa setTextureTarget(), samples() +*/ +GLenum QOpenGLFramebufferObjectFormat::textureTarget() const +{ + return d->target; +} + +/*! + Sets the internal format of a framebuffer object's texture or + multisample framebuffer object's color buffer to + \a internalTextureFormat. + + \sa internalTextureFormat() +*/ +void QOpenGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat) +{ + detach(); + d->internal_format = internalTextureFormat; +} + +/*! + Returns the internal format of a framebuffer object's texture or + multisample framebuffer object's color buffer. The default is + \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on + OpenGL/ES systems. + + \sa setInternalTextureFormat() +*/ +GLenum QOpenGLFramebufferObjectFormat::internalTextureFormat() const +{ + return d->internal_format; +} + +/*! + Returns true if all the options of this framebuffer object format + are the same as \a other; otherwise returns false. +*/ +bool QOpenGLFramebufferObjectFormat::operator==(const QOpenGLFramebufferObjectFormat& other) const +{ + if (d == other.d) + return true; + else + return d->equals(other.d); +} + +/*! + Returns false if all the options of this framebuffer object format + are the same as \a other; otherwise returns true. +*/ +bool QOpenGLFramebufferObjectFormat::operator!=(const QOpenGLFramebufferObjectFormat& other) const +{ + return !(*this == other); +} + +void QOpenGLFBOGLPaintDevice::setFBO(QOpenGLFramebufferObject* f, + QOpenGLFramebufferObject::Attachment attachment) +{ + fbo = f; + m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed + + // The context that the fbo was created in may not have depth + // and stencil buffers, but the fbo itself might. + fboFormat = QOpenGLContext::currentContext()->format(); + if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil) { + fboFormat.setDepthBufferSize(24); + fboFormat.setStencilBufferSize(8); + } else if (attachment == QOpenGLFramebufferObject::Depth) { + fboFormat.setDepthBufferSize(24); + fboFormat.setStencilBufferSize(0); + } else { + fboFormat.setDepthBufferSize(0); + fboFormat.setStencilBufferSize(0); + } + + GLenum format = f->format().internalTextureFormat(); + reqAlpha = (format != GL_RGB +#ifndef QT_OPENGL_ES + && format != GL_RGB5 && format != GL_RGB8 +#endif + ); +} + +QOpenGLContextGroup *QOpenGLFBOGLPaintDevice::group() const +{ + QOpenGLSharedResourceGuard *fbo_guard = + fbo->d_func()->fbo_guard; + return fbo_guard ? fbo_guard->group() : 0; +} + +bool QOpenGLFramebufferObjectPrivate::checkFramebufferStatus() const +{ + QOPENGL_FUNCP_CONTEXT; + if (!ctx) + return false; // Context no longer exists. + GLenum status = QOpenGLFunctions(ctx).glCheckFramebufferStatus(GL_FRAMEBUFFER); + switch(status) { + case GL_NO_ERROR: + case GL_FRAMEBUFFER_COMPLETE: + return true; + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + qDebug("QOpenGLFramebufferObject: Unsupported framebuffer format."); + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + qDebug("QOpenGLFramebufferObject: Framebuffer incomplete attachment."); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing attachment."); + break; +#ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT + case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT: + qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, duplicate attachment."); + break; +#endif + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions."); + break; +#if 1 + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS: + qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attached images must have same format."); + break; + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing draw buffer."); + break; + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing read buffer."); + break; + case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: + qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel."); + break; +#endif + default: + qDebug() <<"QOpenGLFramebufferObject: An undefined error has occurred: "<< status; + break; + } + return false; +} + +namespace +{ + void freeFramebufferFunc(QOpenGLFunctions *funcs, GLuint id) + { + funcs->glDeleteFramebuffers(1, &id); + } + + void freeRenderbufferFunc(QOpenGLFunctions *funcs, GLuint id) + { + funcs->glDeleteRenderbuffers(1, &id); + } + + void freeTextureFunc(QOpenGLFunctions *, GLuint id) + { + glDeleteTextures(1, &id); + } +} + +void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *q, const QSize &sz, + QOpenGLFramebufferObject::Attachment attachment, + GLenum texture_target, GLenum internal_format, + GLint samples, bool mipmap) +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + + funcs.initializeGLFunctions(); + + if (!funcs.hasOpenGLFeature(QOpenGLFunctions::Framebuffers)) + return; + + size = sz; + target = texture_target; + // texture dimensions + + QT_RESET_GLERROR(); // reset error state + GLuint fbo = 0; + + funcs.glGenFramebuffers(1, &fbo); + funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + GLuint texture = 0; + GLuint color_buffer = 0; + GLuint depth_buffer = 0; + GLuint stencil_buffer = 0; + + QT_CHECK_GLERROR(); + // init texture + if (samples == 0) { + glGenTextures(1, &texture); + glBindTexture(target, texture); + glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + if (mipmap) + funcs.glGenerateMipmap(GL_TEXTURE_2D); +#ifndef QT_OPENGL_ES + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#else + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#endif + funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + target, texture, 0); + + QT_CHECK_GLERROR(); + valid = checkFramebufferStatus(); + glBindTexture(target, 0); + + color_buffer = 0; + } else { + mipmap = false; + GLint maxSamples; + glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); + + samples = qBound(0, int(samples), int(maxSamples)); + + funcs.glGenRenderbuffers(1, &color_buffer); + funcs.glBindRenderbuffer(GL_RENDERBUFFER, color_buffer); + if (funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample) && samples > 0) { + funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + internal_format, size.width(), size.height()); + } else { + samples = 0; + funcs.glRenderbufferStorage(GL_RENDERBUFFER, internal_format, + size.width(), size.height()); + } + + funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, color_buffer); + + QT_CHECK_GLERROR(); + valid = checkFramebufferStatus(); + + if (valid) + funcs.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples); + } + + // In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a + // separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer + // might not be supported while separate buffers are, according to QTBUG-12861. + + if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil + && funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil)) + { + // depth and stencil buffer needs another extension + funcs.glGenRenderbuffers(1, &depth_buffer); + Q_ASSERT(!funcs.glIsRenderbuffer(depth_buffer)); + funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); + Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer)); + if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) + funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + GL_DEPTH24_STENCIL8, size.width(), size.height()); + else + funcs.glRenderbufferStorage(GL_RENDERBUFFER, + GL_DEPTH24_STENCIL8, size.width(), size.height()); + + stencil_buffer = depth_buffer; + funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depth_buffer); + funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, stencil_buffer); + + valid = checkFramebufferStatus(); + if (!valid) { + funcs.glDeleteRenderbuffers(1, &depth_buffer); + stencil_buffer = depth_buffer = 0; + } + } + + if (depth_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil + || (attachment == QOpenGLFramebufferObject::Depth))) + { + funcs.glGenRenderbuffers(1, &depth_buffer); + Q_ASSERT(!funcs.glIsRenderbuffer(depth_buffer)); + funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); + Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer)); + if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) { +#ifdef QT_OPENGL_ES + if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { + funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + GL_DEPTH_COMPONENT24, size.width(), size.height()); + } else { + funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + GL_DEPTH_COMPONENT16, size.width(), size.height()); + } +#else + funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + GL_DEPTH_COMPONENT, size.width(), size.height()); +#endif + } else { +#ifdef QT_OPENGL_ES + if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { + funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, + size.width(), size.height()); + } else { + funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, + size.width(), size.height()); + } +#else + funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.width(), size.height()); +#endif + } + funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depth_buffer); + valid = checkFramebufferStatus(); + if (!valid) { + funcs.glDeleteRenderbuffers(1, &depth_buffer); + depth_buffer = 0; + } + } + + if (stencil_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil)) { + funcs.glGenRenderbuffers(1, &stencil_buffer); + Q_ASSERT(!funcs.glIsRenderbuffer(stencil_buffer)); + funcs.glBindRenderbuffer(GL_RENDERBUFFER, stencil_buffer); + Q_ASSERT(funcs.glIsRenderbuffer(stencil_buffer)); + if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) { +#ifdef QT_OPENGL_ES + funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + GL_STENCIL_INDEX8, size.width(), size.height()); +#else + funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + GL_STENCIL_INDEX, size.width(), size.height()); +#endif + } else { +#ifdef QT_OPENGL_ES + funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, + size.width(), size.height()); +#else + funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX, + size.width(), size.height()); +#endif + } + funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, stencil_buffer); + valid = checkFramebufferStatus(); + if (!valid) { + funcs.glDeleteRenderbuffers(1, &stencil_buffer); + stencil_buffer = 0; + } + } + + // The FBO might have become valid after removing the depth or stencil buffer. + valid = checkFramebufferStatus(); + + if (depth_buffer && stencil_buffer) { + fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil; + } else if (depth_buffer) { + fbo_attachment = QOpenGLFramebufferObject::Depth; + } else { + fbo_attachment = QOpenGLFramebufferObject::NoAttachment; + } + + funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo); + if (valid) { + fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc); + if (color_buffer) + color_buffer_guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc); + else + texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc); + if (depth_buffer) + depth_buffer_guard = new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc); + if (stencil_buffer) { + if (stencil_buffer == depth_buffer) + stencil_buffer_guard = depth_buffer_guard; + else + stencil_buffer_guard = new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc); + } + } else { + if (color_buffer) + funcs.glDeleteRenderbuffers(1, &color_buffer); + else + glDeleteTextures(1, &texture); + if (depth_buffer) + funcs.glDeleteRenderbuffers(1, &depth_buffer); + if (stencil_buffer && depth_buffer != stencil_buffer) + funcs.glDeleteRenderbuffers(1, &stencil_buffer); + funcs.glDeleteFramebuffers(1, &fbo); + } + QT_CHECK_GLERROR(); + + format.setTextureTarget(target); + format.setSamples(int(samples)); + format.setAttachment(fbo_attachment); + format.setInternalTextureFormat(internal_format); + format.setMipmap(mipmap); + + glDevice.setFBO(q, attachment); +} + +/*! + \class QOpenGLFramebufferObject + \brief The QOpenGLFramebufferObject class encapsulates an OpenGL framebuffer object. + \since 4.2 + + \ingroup painting-3D + + The QOpenGLFramebufferObject class encapsulates an OpenGL framebuffer + object, defined by the \c{GL_EXT_framebuffer_object} extension. In + addition it provides a rendering surface that can be painted on + with a QPainter, rendered to using native GL calls, or both. This + surface can be bound and used as a regular texture in your own GL + drawing code. By default, the QOpenGLFramebufferObject class + generates a 2D GL texture (using the \c{GL_TEXTURE_2D} target), + which is used as the internal rendering target. + + \bold{It is important to have a current GL context when creating a + QOpenGLFramebufferObject, otherwise initialization will fail.} + + OpenGL framebuffer objects and pbuffers (see + \l{QOpenGLPixelBuffer}{QOpenGLPixelBuffer}) can both be used to render to + offscreen surfaces, but there are a number of advantages with + using framebuffer objects instead of pbuffers: + + \list 1 + \o A framebuffer object does not require a separate rendering + context, so no context switching will occur when switching + rendering targets. There is an overhead involved in switching + targets, but in general it is cheaper than a context switch to a + pbuffer. + + \o Rendering to dynamic textures (i.e. render-to-texture + functionality) works on all platforms. No need to do explicit copy + calls from a render buffer into a texture, as was necessary on + systems that did not support the \c{render_texture} extension. + + \o It is possible to attach several rendering buffers (or texture + objects) to the same framebuffer object, and render to all of them + without doing a context switch. + + \o The OpenGL framebuffer extension is a pure GL extension with no + system dependant WGL, CGL, or GLX parts. This makes using + framebuffer objects more portable. + \endlist + + When using a QPainter to paint to a QOpenGLFramebufferObject you should take + care that the QOpenGLFramebufferObject is created with the CombinedDepthStencil + attachment for QPainter to be able to render correctly. + Note that you need to create a QOpenGLFramebufferObject with more than one + sample per pixel for primitives to be antialiased when drawing using a + QPainter. To create a multisample framebuffer object you should use one of + the constructors that take a QOpenGLFramebufferObject parameter, and set the + QOpenGLFramebufferObject::samples() property to a non-zero value. + + When painting to a QOpenGLFramebufferObject using QPainter, the state of + the current GL context will be altered by the paint engine to reflect + its needs. Applications should not rely upon the GL state being reset + to its original conditions, particularly the current shader program, + GL viewport, texture units, and drawing modes. + + For multisample framebuffer objects a color render buffer is created, + otherwise a texture with the specified texture target is created. + The color render buffer or texture will have the specified internal + format, and will be bound to the \c GL_COLOR_ATTACHMENT0 + attachment in the framebuffer object. + + If you want to use a framebuffer object with multisampling enabled + as a texture, you first need to copy from it to a regular framebuffer + object using QOpenGLContext::blitFramebuffer(). + + \section1 Threading + + As of Qt 4.8, it's possible to draw into a QOpenGLFramebufferObject + using a QPainter in a separate thread. Note that OpenGL 2.0 or + OpenGL ES 2.0 is required for this to work. + + \sa {Framebuffer Object Example} +*/ + + +/*! + \enum QOpenGLFramebufferObject::Attachment + \since 4.3 + + This enum type is used to configure the depth and stencil buffers + attached to the framebuffer object when it is created. + + \value NoAttachment No attachment is added to the framebuffer object. Note that the + OpenGL depth and stencil tests won't work when rendering to a + framebuffer object without any depth or stencil buffers. + This is the default value. + + \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present, + a combined depth and stencil buffer is attached. + If the extension is not present, only a depth buffer is attached. + + \value Depth A depth buffer is attached to the framebuffer object. + + \sa attachment() +*/ + + +/*! \fn QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, GLenum target) + + Constructs an OpenGL framebuffer object and binds a 2D GL texture + to the buffer of the size \a size. The texture is bound to the + \c GL_COLOR_ATTACHMENT0 target in the framebuffer object. + + The \a target parameter is used to specify the GL texture + target. The default target is \c GL_TEXTURE_2D. Keep in mind that + \c GL_TEXTURE_2D textures must have a power of 2 width and height + (e.g. 256x512), unless you are using OpenGL 2.0 or higher. + + By default, no depth and stencil buffers are attached. This behavior + can be toggled using one of the overloaded constructors. + + The default internal texture format is \c GL_RGBA8 for desktop + OpenGL, and \c GL_RGBA for OpenGL/ES. + + It is important that you have a current GL context set when + creating the QOpenGLFramebufferObject, otherwise the initialization + will fail. + + \sa size(), texture(), attachment() +*/ + +QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, GLenum target) + : d_ptr(new QOpenGLFramebufferObjectPrivate) +{ + Q_D(QOpenGLFramebufferObject); + d->init(this, size, NoAttachment, target, DEFAULT_FORMAT); +} + +/*! \overload + + Constructs an OpenGL framebuffer object and binds a 2D GL texture + to the buffer of the given \a width and \a height. + + \sa size(), texture() +*/ +QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, GLenum target) + : d_ptr(new QOpenGLFramebufferObjectPrivate) +{ + Q_D(QOpenGLFramebufferObject); + d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT); +} + +/*! \overload + + Constructs an OpenGL framebuffer object of the given \a size based on the + supplied \a format. +*/ + +QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, const QOpenGLFramebufferObjectFormat &format) + : d_ptr(new QOpenGLFramebufferObjectPrivate) +{ + Q_D(QOpenGLFramebufferObject); + d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(), + format.samples(), format.mipmap()); +} + +/*! \overload + + Constructs an OpenGL framebuffer object of the given \a width and \a height + based on the supplied \a format. +*/ + +QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, const QOpenGLFramebufferObjectFormat &format) + : d_ptr(new QOpenGLFramebufferObjectPrivate) +{ + Q_D(QOpenGLFramebufferObject); + d->init(this, QSize(width, height), format.attachment(), format.textureTarget(), + format.internalTextureFormat(), format.samples(), format.mipmap()); +} + +/*! \overload + + Constructs an OpenGL framebuffer object and binds a texture to the + buffer of the given \a width and \a height. + + The \a attachment parameter describes the depth/stencil buffer + configuration, \a target the texture target and \a internal_format + the internal texture format. The default texture target is \c + GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8 + for desktop OpenGL and \c GL_RGBA for OpenGL/ES. + + \sa size(), texture(), attachment() +*/ +QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, Attachment attachment, + GLenum target, GLenum internal_format) + : d_ptr(new QOpenGLFramebufferObjectPrivate) +{ + Q_D(QOpenGLFramebufferObject); + d->init(this, QSize(width, height), attachment, target, internal_format); +} + +/*! \overload + + Constructs an OpenGL framebuffer object and binds a texture to the + buffer of the given \a size. + + The \a attachment parameter describes the depth/stencil buffer + configuration, \a target the texture target and \a internal_format + the internal texture format. The default texture target is \c + GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8 + for desktop OpenGL and \c GL_RGBA for OpenGL/ES. + + \sa size(), texture(), attachment() +*/ +QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, Attachment attachment, + GLenum target, GLenum internal_format) + : d_ptr(new QOpenGLFramebufferObjectPrivate) +{ + Q_D(QOpenGLFramebufferObject); + d->init(this, size, attachment, target, internal_format); +} + +/*! + \fn QOpenGLFramebufferObject::~QOpenGLFramebufferObject() + + Destroys the framebuffer object and frees any allocated resources. +*/ +QOpenGLFramebufferObject::~QOpenGLFramebufferObject() +{ + Q_D(QOpenGLFramebufferObject); + + delete d->engine; + + if (d->texture_guard) + d->texture_guard->free(); + if (d->color_buffer_guard) + d->color_buffer_guard->free(); + if (d->depth_buffer_guard) + d->depth_buffer_guard->free(); + if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard) + d->stencil_buffer_guard->free(); + if (d->fbo_guard) + d->fbo_guard->free(); +} + +/*! + \fn bool QOpenGLFramebufferObject::isValid() const + + Returns true if the framebuffer object is valid. + + The framebuffer can become invalid if the initialization process + fails, the user attaches an invalid buffer to the framebuffer + object, or a non-power of two width/height is specified as the + texture size if the texture target is \c{GL_TEXTURE_2D}. + The non-power of two limitation does not apply if the OpenGL version + is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension + is present. + + The framebuffer can also become invalid if the QOpenGLContext that + the framebuffer was created within is destroyed and there are + no other shared contexts that can take over ownership of the + framebuffer. +*/ +bool QOpenGLFramebufferObject::isValid() const +{ + Q_D(const QOpenGLFramebufferObject); + return d->valid && d->fbo_guard && d->fbo_guard->id(); +} + +/*! + \fn bool QOpenGLFramebufferObject::bind() + + Switches rendering from the default, windowing system provided + framebuffer to this framebuffer object. + Returns true upon success, false otherwise. + + \sa release() +*/ +bool QOpenGLFramebufferObject::bind() +{ + if (!isValid()) + return false; + Q_D(QOpenGLFramebufferObject); + QOPENGL_FUNC_CONTEXT; + if (!ctx) + return false; // Context no longer exists. + QOpenGLContext *current = QOpenGLContext::currentContext(); +#ifdef QT_DEBUG + if (!current || current->shareGroup() != d->fbo_guard->group()) + qWarning("QOpenGLFramebufferObject::bind() called from incompatible context"); +#endif + d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); + d->valid = d->checkFramebufferStatus(); + if (d->valid && current) + current->d_func()->current_fbo = d->fbo(); + return d->valid; +} + +/*! + \fn bool QOpenGLFramebufferObject::release() + + Switches rendering back to the default, windowing system provided + framebuffer. + Returns true upon success, false otherwise. + + \sa bind() +*/ +bool QOpenGLFramebufferObject::release() +{ + if (!isValid()) + return false; + QOPENGL_FUNC_CONTEXT; + if (!ctx) + return false; // Context no longer exists. + + QOpenGLContext *current = QOpenGLContext::currentContext(); + +#ifdef QT_DEBUG + Q_D(QOpenGLFramebufferObject); + if (!current || current->shareGroup() != d->fbo_guard->group()) + qWarning("QOpenGLFramebufferObject::release() called from incompatible context"); +#endif + + if (current) { + current->d_func()->current_fbo = current->d_func()->default_fbo; + d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_func()->default_fbo); + } + + return true; +} + +/*! + \fn GLuint QOpenGLFramebufferObject::texture() const + + Returns the texture id for the texture attached as the default + rendering target in this framebuffer object. This texture id can + be bound as a normal texture in your own GL code. + + If a multisample framebuffer object is used then the value returned + from this function will be invalid. +*/ +GLuint QOpenGLFramebufferObject::texture() const +{ + Q_D(const QOpenGLFramebufferObject); + return d->texture_guard ? d->texture_guard->id() : 0; +} + +/*! + \fn QSize QOpenGLFramebufferObject::size() const + + Returns the size of the texture attached to this framebuffer + object. +*/ +QSize QOpenGLFramebufferObject::size() const +{ + Q_D(const QOpenGLFramebufferObject); + return d->size; +} + +/*! + Returns the format of this framebuffer object. +*/ +QOpenGLFramebufferObjectFormat QOpenGLFramebufferObject::format() const +{ + Q_D(const QOpenGLFramebufferObject); + return d->format; +} + +namespace { +/* + Read back the contents of the currently bound framebuffer, used in + QGLWidget::grabFrameBuffer(), QGLPixelbuffer::toImage() and + QGLFramebufferObject::toImage() +*/ + +void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, bool include_alpha) +{ + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { + // OpenGL gives RGBA; Qt wants ARGB + uint *p = (uint*)img.bits(); + uint *end = p + w*h; + if (alpha_format && include_alpha) { + while (p < end) { + uint a = *p << 24; + *p = (*p >> 8) | a; + p++; + } + } else { + // This is an old legacy fix for PowerPC based Macs, which + // we shouldn't remove + while (p < end) { + *p = 0xff000000 | (*p>>8); + ++p; + } + } + } else { + // OpenGL gives ABGR (i.e. RGBA backwards); Qt wants ARGB + for (int y = 0; y < h; y++) { + uint *q = (uint*)img.scanLine(y); + for (int x=0; x < w; ++x) { + const uint pixel = *q; + if (alpha_format && include_alpha) { + *q = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) + | (pixel & 0xff00ff00); + } else { + *q = 0xff000000 | ((pixel << 16) & 0xff0000) + | ((pixel >> 16) & 0xff) | (pixel & 0x00ff00); + } + + q++; + } + } + + } + img = img.mirrored(); +} + +} + +Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) +{ + QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32_Premultiplied + : QImage::Format_RGB32); + int w = size.width(); + int h = size.height(); + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); + convertFromGLImage(img, w, h, alpha_format, include_alpha); + return img; +} + +/*! + \fn QImage QOpenGLFramebufferObject::toImage() const + + Returns the contents of this framebuffer object as a QImage. +*/ +QImage QOpenGLFramebufferObject::toImage() const +{ + Q_D(const QOpenGLFramebufferObject); + if (!d->valid) + return QImage(); + + // qt_gl_read_framebuffer doesn't work on a multisample FBO + if (format().samples() != 0) { + QOpenGLFramebufferObject temp(size(), QOpenGLFramebufferObjectFormat()); + + QRect rect(QPoint(0, 0), size()); + blitFramebuffer(&temp, rect, const_cast(this), rect); + + return temp.toImage(); + } + + bool wasBound = isBound(); + if (!wasBound) + const_cast(this)->bind(); + QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true); + if (!wasBound) + const_cast(this)->release(); + + return image; +} + +Q_GLOBAL_STATIC(QOpenGLEngineThreadStorage, qt_buffer_2_engine) + +/*! \reimp */ +QPaintEngine *QOpenGLFramebufferObject::paintEngine() const +{ + Q_D(const QOpenGLFramebufferObject); + if (d->engine) + return d->engine; + + QPaintEngine *engine = qt_buffer_2_engine()->engine(); + if (engine->isActive() && engine->paintDevice() != this) { + d->engine = new QOpenGL2PaintEngineEx; + return d->engine; + } + return engine; +} + +/*! + \fn bool QOpenGLFramebufferObject::bindDefault() + \internal + + Switches rendering back to the default, windowing system provided + framebuffer. + Returns true upon success, false otherwise. + + \sa bind(), release() +*/ +bool QOpenGLFramebufferObject::bindDefault() +{ + QOpenGLContext *ctx = const_cast(QOpenGLContext::currentContext()); + QOpenGLFunctions functions(ctx); + + if (ctx) { + ctx->d_func()->current_fbo = ctx->d_func()->default_fbo; + functions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->default_fbo); +#ifdef QT_DEBUG + } else { + qWarning("QOpenGLFramebufferObject::bindDefault() called without current context."); +#endif + } + + return ctx != 0; +} + +/*! + \fn bool QOpenGLFramebufferObject::hasOpenGLFramebufferObjects() + + Returns true if the OpenGL \c{GL_EXT_framebuffer_object} extension + is present on this system; otherwise returns false. +*/ +bool QOpenGLFramebufferObject::hasOpenGLFramebufferObjects() +{ + return QOpenGLFunctions(QOpenGLContext::currentContext()).hasOpenGLFeature(QOpenGLFunctions::Framebuffers); +} + +/*! \reimp */ +int QOpenGLFramebufferObject::metric(PaintDeviceMetric metric) const +{ + Q_D(const QOpenGLFramebufferObject); + + float dpmx = qt_defaultDpiX()*100./2.54; + float dpmy = qt_defaultDpiY()*100./2.54; + int w = d->size.width(); + int h = d->size.height(); + switch (metric) { + case PdmWidth: + return w; + + case PdmHeight: + return h; + + case PdmWidthMM: + return qRound(w * 1000 / dpmx); + + case PdmHeightMM: + return qRound(h * 1000 / dpmy); + + case PdmNumColors: + return 0; + + case PdmDepth: + return 32;//d->depth; + + case PdmDpiX: + return qRound(dpmx * 0.0254); + + case PdmDpiY: + return qRound(dpmy * 0.0254); + + case PdmPhysicalDpiX: + return qRound(dpmx * 0.0254); + + case PdmPhysicalDpiY: + return qRound(dpmy * 0.0254); + + default: + qWarning("QOpenGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric); + break; + } + return 0; +} + +/*! + \fn GLuint QOpenGLFramebufferObject::handle() const + + Returns the GL framebuffer object handle for this framebuffer + object (returned by the \c{glGenFrameBuffersEXT()} function). This + handle can be used to attach new images or buffers to the + framebuffer. The user is responsible for cleaning up and + destroying these objects. +*/ +GLuint QOpenGLFramebufferObject::handle() const +{ + Q_D(const QOpenGLFramebufferObject); + return d->fbo(); +} + +/*! \fn int QOpenGLFramebufferObject::devType() const + \internal +*/ + + +/*! + Returns the status of the depth and stencil buffers attached to + this framebuffer object. +*/ + +QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObject::attachment() const +{ + Q_D(const QOpenGLFramebufferObject); + if (d->valid) + return d->fbo_attachment; + return NoAttachment; +} + +/*! + \since 4.5 + + Returns true if the framebuffer object is currently bound to a context, + otherwise false is returned. +*/ + +bool QOpenGLFramebufferObject::isBound() const +{ + Q_D(const QOpenGLFramebufferObject); + QOpenGLContext *current = QOpenGLContext::currentContext(); + return current ? current->d_func()->current_fbo == d->fbo() : false; +} + +/*! + \fn bool QOpenGLFramebufferObject::hasOpenGLFramebufferBlit() + + \since 4.6 + + Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension + is present on this system; otherwise returns false. + + \sa blitFramebuffer() +*/ +bool QOpenGLFramebufferObject::hasOpenGLFramebufferBlit() +{ + return QOpenGLExtensions(QOpenGLContext::currentContext()).hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit); +} + +/*! + \since 4.6 + + Blits from the \a sourceRect rectangle in the \a source framebuffer + object to the \a targetRect rectangle in the \a target framebuffer object. + + If \a source or \a target is 0, the default framebuffer will be used + instead of a framebuffer object as source or target respectively. + + The \a buffers parameter should be a mask consisting of any combination of + \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and + \c GL_STENCIL_BUFFER_BIT. Any buffer type that is not present both + in the source and target buffers is ignored. + + The \a sourceRect and \a targetRect rectangles may have different sizes; + in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or + \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to + \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest + interpolation should be used when scaling is performed. + + If \a source equals \a target a copy is performed within the same buffer. + Results are undefined if the source and target rectangles overlap and + have different sizes. The sizes must also be the same if any of the + framebuffer objects are multisample framebuffers. + + Note that the scissor test will restrict the blit area if enabled. + + This function will have no effect unless hasOpenGLFramebufferBlit() returns + true. + + \sa hasOpenGLFramebufferBlit() +*/ +void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect, + QOpenGLFramebufferObject *source, const QRect &sourceRect, + GLbitfield buffers, + GLenum filter) +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx) + return; + + QOpenGLExtensions extensions(ctx); + if (!extensions.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) + return; + + QSurface *surface = ctx->surface(); + + const int height = static_cast(surface)->height(); + + const int sh = source ? source->height() : height; + const int th = target ? target->height() : height; + + const int sx0 = sourceRect.left(); + const int sx1 = sourceRect.left() + sourceRect.width(); + const int sy0 = sh - (sourceRect.top() + sourceRect.height()); + const int sy1 = sh - sourceRect.top(); + + const int tx0 = targetRect.left(); + const int tx1 = targetRect.left() + targetRect.width(); + const int ty0 = th - (targetRect.top() + targetRect.height()); + const int ty1 = th - targetRect.top(); + + extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : 0); + extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : 0); + + extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1, + tx0, ty0, tx1, ty1, + buffers, filter); + + extensions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo); +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglframebufferobject.h b/src/gui/opengl/qopenglframebufferobject.h new file mode 100644 index 0000000000..d1bd09c629 --- /dev/null +++ b/src/gui/opengl/qopenglframebufferobject.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLFRAMEBUFFEROBJECT_H +#define QOPENGLFRAMEBUFFEROBJECT_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QOpenGLFramebufferObjectPrivate; +class QOpenGLFramebufferObjectFormat; + +class Q_GUI_EXPORT QOpenGLFramebufferObject : public QPaintDevice +{ + Q_DECLARE_PRIVATE(QOpenGLFramebufferObject) +public: + enum Attachment { + NoAttachment, + CombinedDepthStencil, + Depth + }; + + QOpenGLFramebufferObject(const QSize &size, GLenum target = GL_TEXTURE_2D); + QOpenGLFramebufferObject(int width, int height, GLenum target = GL_TEXTURE_2D); +#if !defined(QT_OPENGL_ES) || defined(Q_QDOC) + QOpenGLFramebufferObject(const QSize &size, Attachment attachment, + GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA8); + QOpenGLFramebufferObject(int width, int height, Attachment attachment, + GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA8); +#else + QOpenGLFramebufferObject(const QSize &size, Attachment attachment, + GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA); + QOpenGLFramebufferObject(int width, int height, Attachment attachment, + GLenum target = GL_TEXTURE_2D, GLenum internal_format = GL_RGBA); +#endif + + QOpenGLFramebufferObject(const QSize &size, const QOpenGLFramebufferObjectFormat &format); + QOpenGLFramebufferObject(int width, int height, const QOpenGLFramebufferObjectFormat &format); + + virtual ~QOpenGLFramebufferObject(); + + QOpenGLFramebufferObjectFormat format() const; + + bool isValid() const; + bool isBound() const; + bool bind(); + bool release(); + + GLuint texture() const; + QSize size() const; + QImage toImage() const; + Attachment attachment() const; + + QPaintEngine *paintEngine() const; + GLuint handle() const; + + static bool bindDefault(); + + static bool hasOpenGLFramebufferObjects(); + + static bool hasOpenGLFramebufferBlit(); + static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect, + QOpenGLFramebufferObject *source, const QRect &sourceRect, + GLbitfield buffers = GL_COLOR_BUFFER_BIT, + GLenum filter = GL_NEAREST); + +protected: + int metric(PaintDeviceMetric metric) const; + int devType() const { return QInternal::FramebufferObject; } + +private: + Q_DISABLE_COPY(QOpenGLFramebufferObject) + QScopedPointer d_ptr; + friend class QOpenGLPaintDevice; + friend class QOpenGLFBOGLPaintDevice; +}; + +class QOpenGLFramebufferObjectFormatPrivate; +class Q_GUI_EXPORT QOpenGLFramebufferObjectFormat +{ +public: + QOpenGLFramebufferObjectFormat(); + QOpenGLFramebufferObjectFormat(const QOpenGLFramebufferObjectFormat &other); + QOpenGLFramebufferObjectFormat &operator=(const QOpenGLFramebufferObjectFormat &other); + ~QOpenGLFramebufferObjectFormat(); + + void setSamples(int samples); + int samples() const; + + void setMipmap(bool enabled); + bool mipmap() const; + + void setAttachment(QOpenGLFramebufferObject::Attachment attachment); + QOpenGLFramebufferObject::Attachment attachment() const; + + void setTextureTarget(GLenum target); + GLenum textureTarget() const; + + void setInternalTextureFormat(GLenum internalTextureFormat); + GLenum internalTextureFormat() const; + + bool operator==(const QOpenGLFramebufferObjectFormat& other) const; + bool operator!=(const QOpenGLFramebufferObjectFormat& other) const; + +private: + QOpenGLFramebufferObjectFormatPrivate *d; + + void detach(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER +#endif // QOPENGLFRAMEBUFFEROBJECT_H diff --git a/src/gui/opengl/qopenglframebufferobject_p.h b/src/gui/opengl/qopenglframebufferobject_p.h new file mode 100644 index 0000000000..6ea6eb26ee --- /dev/null +++ b/src/gui/opengl/qopenglframebufferobject_p.h @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLFRAMEBUFFEROBJECT_P_H +#define QOPENGLFRAMEBUFFEROBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +QT_BEGIN_INCLUDE_NAMESPACE + +#include +#include +#include +#include + +QT_END_INCLUDE_NAMESPACE + +#ifndef QT_OPENGL_ES +#define DEFAULT_FORMAT GL_RGBA8 +#else +#define DEFAULT_FORMAT GL_RGBA +#endif + +class QOpenGLFramebufferObjectFormatPrivate +{ +public: + QOpenGLFramebufferObjectFormatPrivate() + : ref(1), + samples(0), + attachment(QOpenGLFramebufferObject::NoAttachment), + target(GL_TEXTURE_2D), + internal_format(DEFAULT_FORMAT), + mipmap(false) + { + } + QOpenGLFramebufferObjectFormatPrivate + (const QOpenGLFramebufferObjectFormatPrivate *other) + : ref(1), + samples(other->samples), + attachment(other->attachment), + target(other->target), + internal_format(other->internal_format), + mipmap(other->mipmap) + { + } + bool equals(const QOpenGLFramebufferObjectFormatPrivate *other) + { + return samples == other->samples && + attachment == other->attachment && + target == other->target && + internal_format == other->internal_format && + mipmap == other->mipmap; + } + + QAtomicInt ref; + int samples; + QOpenGLFramebufferObject::Attachment attachment; + GLenum target; + GLenum internal_format; + uint mipmap : 1; +}; + +class QOpenGLFBOGLPaintDevice : public QOpenGLPaintDevice +{ +public: + virtual QPaintEngine* paintEngine() const {return fbo->paintEngine();} + virtual QSize size() const {return fbo->size();} + virtual QSurfaceFormat format() const {return fboFormat;} + virtual QOpenGLContextGroup *group() const; + virtual bool alphaRequested() const { return reqAlpha; } + + void setFBO(QOpenGLFramebufferObject* f, + QOpenGLFramebufferObject::Attachment attachment); + +private: + QOpenGLFramebufferObject* fbo; + QSurfaceFormat fboFormat; + bool wasBound; + bool reqAlpha; +}; + +class QOpenGLFramebufferObjectPrivate +{ +public: + QOpenGLFramebufferObjectPrivate() : fbo_guard(0), texture_guard(0), depth_buffer_guard(0) + , stencil_buffer_guard(0), color_buffer_guard(0) + , valid(false), engine(0) {} + ~QOpenGLFramebufferObjectPrivate() {} + + void init(QOpenGLFramebufferObject *q, const QSize& sz, + QOpenGLFramebufferObject::Attachment attachment, + GLenum internal_format, GLenum texture_target, + GLint samples = 0, bool mipmap = false); + bool checkFramebufferStatus() const; + QOpenGLSharedResourceGuard *fbo_guard; + QOpenGLSharedResourceGuard *texture_guard; + QOpenGLSharedResourceGuard *depth_buffer_guard; + QOpenGLSharedResourceGuard *stencil_buffer_guard; + QOpenGLSharedResourceGuard *color_buffer_guard; + GLenum target; + QSize size; + QOpenGLFramebufferObjectFormat format; + uint valid : 1; + QOpenGLFramebufferObject::Attachment fbo_attachment; + mutable QPaintEngine *engine; + QOpenGLFBOGLPaintDevice glDevice; + QOpenGLExtensions funcs; + + inline GLuint fbo() const { return fbo_guard ? fbo_guard->id() : 0; } +}; + + +QT_END_NAMESPACE + +#endif // QOPENGLFRAMEBUFFEROBJECT_P_H diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp new file mode 100644 index 0000000000..4ef80bfa89 --- /dev/null +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -0,0 +1,2452 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenglfunctions.h" +#include "qopenglextensions_p.h" +#include "qdebug.h" +#include "QtGui/private/qopenglcontext_p.h" +#include "QtGui/private/qopengl_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QOpenGLFunctions + \brief The QOpenGLFunctions class provides cross-platform access to the OpenGL/ES 2.0 API. + \since 4.8 + \ingroup painting-3D + + OpenGL/ES 2.0 defines a subset of the OpenGL specification that is + common across many desktop and embedded OpenGL implementations. + However, it can be difficult to use the functions from that subset + because they need to be resolved manually on desktop systems. + + QOpenGLFunctions provides a guaranteed API that is available on all + OpenGL systems and takes care of function resolution on systems + that need it. The recommended way to use QOpenGLFunctions is by + direct inheritance: + + \code + class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions + { + Q_OBJECT + public: + MyGLWidget(QWidget *parent = 0) : QOpenGLWidget(parent) {} + + protected: + void initializeGL(); + void paintGL(); + }; + + void MyGLWidget::initializeGL() + { + initializeGLFunctions(); + } + \endcode + + The \c{paintGL()} function can then use any of the OpenGL/ES 2.0 + functions without explicit resolution, such as glActiveTexture() + in the following example: + + \code + void MyGLWidget::paintGL() + { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, textureId); + ... + } + \endcode + + QOpenGLFunctions can also be used directly for ad-hoc invocation + of OpenGL/ES 2.0 functions on all platforms: + + \code + QOpenGLFunctions glFuncs(QOpenGLContext::currentContext()); + glFuncs.glActiveTexture(GL_TEXTURE1); + \endcode + + QOpenGLFunctions provides wrappers for all OpenGL/ES 2.0 functions, + except those like \c{glDrawArrays()}, \c{glViewport()}, and + \c{glBindTexture()} that don't have portability issues. + + Including the header for QOpenGLFunctions will also define all of + the OpenGL/ES 2.0 macro constants that are not already defined by + the system's OpenGL headers, such as \c{GL_TEXTURE1} above. + + The hasOpenGLFeature() and openGLFeatures() functions can be used + to determine if the OpenGL implementation has a major OpenGL/ES 2.0 + feature. For example, the following checks if non power of two + textures are available: + + \code + QOpenGLFunctions funcs(QOpenGLContext::currentContext()); + bool npot = funcs.hasOpenGLFeature(QOpenGLFunctions::NPOTTextures); + \endcode +*/ + +/*! + \enum QOpenGLFunctions::OpenGLFeature + This enum defines OpenGL/ES 2.0 features that may be optional + on other platforms. + + \value Multitexture glActiveTexture() function is available. + \value Shaders Shader functions are available. + \value Buffers Vertex and index buffer functions are available. + \value Framebuffers Framebuffer object functions are available. + \value BlendColor glBlendColor() is available. + \value BlendEquation glBlendEquation() is available. + \value BlendEquationSeparate glBlendEquationSeparate() is available. + \value BlendFuncSeparate glBlendFuncSeparate() is available. + \value BlendSubtract Blend subtract mode is available. + \value CompressedTextures Compressed texture functions are available. + \value Multisample glSampleCoverage() function is available. + \value StencilSeparate Separate stencil functions are available. + \value NPOTTextures Non power of two textures are available. +*/ + +// Hidden private fields for additional extension data. +struct QOpenGLFunctionsPrivateEx : public QOpenGLExtensionsPrivate, public QOpenGLSharedResource +{ + QOpenGLFunctionsPrivateEx(QOpenGLContext *context) + : QOpenGLExtensionsPrivate(context) + , QOpenGLSharedResource(context->shareGroup()) + , m_features(-1) + , m_extensions(-1) + {} + + void invalidateResource() + { + m_features = -1; + m_extensions = -1; + } + + void freeResource(QOpenGLContext *) + { + // no gl resources to free + } + + int m_features; + int m_extensions; +}; + +Q_GLOBAL_STATIC(QOpenGLMultiGroupSharedResource, qt_gl_functions_resource) + +static QOpenGLFunctionsPrivateEx *qt_gl_functions(QOpenGLContext *context = 0) +{ + if (!context) + context = QOpenGLContext::currentContext(); + Q_ASSERT(context); + QOpenGLFunctionsPrivateEx *funcs = + qt_gl_functions_resource()->value(context); + return funcs; +} + +/*! + Constructs a default function resolver. The resolver cannot + be used until initializeGLFunctions() is called to specify + the context. + + \sa initializeGLFunctions() +*/ +QOpenGLFunctions::QOpenGLFunctions() + : d_ptr(0) +{ +} + +/*! + Constructs a function resolver for \a context. If \a context + is null, then the resolver will be created for the current QOpenGLContext. + + The context or another context in the group must be current. + + An object constructed in this way can only be used with \a context + and other contexts that share with it. Use initializeGLFunctions() + to change the object's context association. + + \sa initializeGLFunctions() +*/ +QOpenGLFunctions::QOpenGLFunctions(QOpenGLContext *context) + : d_ptr(0) +{ + if (context && QOpenGLContextGroup::currentContextGroup() == context->shareGroup()) + d_ptr = qt_gl_functions(); + else + qWarning() << "QOpenGLFunctions created with non-current context"; +} + +QOpenGLExtensions::QOpenGLExtensions() + : QOpenGLFunctions() +{ +} + +QOpenGLExtensions::QOpenGLExtensions(QOpenGLContext *context) + : QOpenGLFunctions(context) +{ +} + +/*! + \fn QOpenGLFunctions::~QOpenGLFunctions() + + Destroys this function resolver. +*/ + +static int qt_gl_resolve_features() +{ +#if defined(QT_OPENGL_ES_2) + int features = QOpenGLFunctions::Multitexture | + QOpenGLFunctions::Shaders | + QOpenGLFunctions::Buffers | + QOpenGLFunctions::Framebuffers | + QOpenGLFunctions::BlendColor | + QOpenGLFunctions::BlendEquation | + QOpenGLFunctions::BlendEquationSeparate | + QOpenGLFunctions::BlendFuncSeparate | + QOpenGLFunctions::BlendSubtract | + QOpenGLFunctions::CompressedTextures | + QOpenGLFunctions::Multisample | + QOpenGLFunctions::StencilSeparate; + QOpenGLExtensionMatcher extensions; + if (extensions.match("GL_OES_texture_npot")) + features |= QOpenGLFunctions::NPOTTextures; + if (extensions.match("GL_IMG_texture_npot")) + features |= QOpenGLFunctions::NPOTTextures; + return features; +#elif defined(QT_OPENGL_ES) + int features = QOpenGLFunctions::Multitexture | + QOpenGLFunctions::Buffers | + QOpenGLFunctions::CompressedTextures | + QOpenGLFunctions::Multisample; + QOpenGLExtensionMatcher extensions; + if (extensions.match("GL_OES_framebuffer_object")) + features |= QOpenGLFunctions::Framebuffers; + if (extensions.match("GL_OES_blend_equation_separate")) + features |= QOpenGLFunctions::BlendEquationSeparate; + if (extensions.match("GL_OES_blend_func_separate")) + features |= QOpenGLFunctions::BlendFuncSeparate; + if (extensions.match("GL_OES_blend_subtract")) + features |= QOpenGLFunctions::BlendSubtract; + if (extensions.match("GL_OES_texture_npot")) + features |= QOpenGLFunctions::NPOTTextures; + if (extensions.match("GL_IMG_texture_npot")) + features |= QOpenGLFunctions::NPOTTextures; + return features; +#else + int features = 0; + //QOpenGLFormat::OpenGLVersionFlags versions = QOpenGLFormat::openGLVersionFlags(); + QOpenGLExtensionMatcher extensions; + + // Recognize features by extension name. + if (extensions.match("GL_ARB_multitexture")) + features |= QOpenGLFunctions::Multitexture; + if (extensions.match("GL_ARB_shader_objects")) + features |= QOpenGLFunctions::Shaders; + if (extensions.match("GL_EXT_framebuffer_object") || + extensions.match("GL_ARB_framebuffer_object")) + features |= QOpenGLFunctions::Framebuffers; + if (extensions.match("GL_EXT_blend_color")) + features |= QOpenGLFunctions::BlendColor; + if (extensions.match("GL_EXT_blend_equation_separate")) + features |= QOpenGLFunctions::BlendEquationSeparate; + if (extensions.match("GL_EXT_blend_func_separate")) + features |= QOpenGLFunctions::BlendFuncSeparate; + if (extensions.match("GL_EXT_blend_subtract")) + features |= QOpenGLFunctions::BlendSubtract; + if (extensions.match("GL_ARB_texture_compression")) + features |= QOpenGLFunctions::CompressedTextures; + if (extensions.match("GL_ARB_multisample")) + features |= QOpenGLFunctions::Multisample; + if (extensions.match("GL_ARB_texture_non_power_of_two")) + features |= QOpenGLFunctions::NPOTTextures; + + // assume version 2.0 or higher + features |= QOpenGLFunctions::BlendColor | + QOpenGLFunctions::BlendEquation | + QOpenGLFunctions::Multitexture | + QOpenGLFunctions::CompressedTextures | + QOpenGLFunctions::Multisample | + QOpenGLFunctions::BlendFuncSeparate | + QOpenGLFunctions::Buffers | + QOpenGLFunctions::Shaders | + QOpenGLFunctions::StencilSeparate | + QOpenGLFunctions::BlendEquationSeparate | + QOpenGLFunctions::NPOTTextures; + return features; +#endif +} + +static int qt_gl_resolve_extensions() +{ + int extensions = 0; + QOpenGLExtensionMatcher extensionMatcher; +#if defined(QT_OPENGL_ES) + if (extensionMatcher.match("GL_OES_mapbuffer")) + extensions |= QOpenGLExtensions::MapBuffer; + if (extensionMatcher.match("GL_OES_packed_depth_stencil")) + extensions |= QOpenGLExtensions::PackedDepthStencil; + if (extensionMatcher.match("GL_OES_element_index_uint")) + extensions |= QOpenGLExtensions::ElementIndexUint; + if (extensionMatcher.match("GL_OES_depth24")) + extensions |= QOpenGLExtensions::Depth24; +#else + extensions |= QOpenGLExtensions::ElementIndexUint | QOpenGLExtensions::MapBuffer; + + // Recognize features by extension name. + if (extensionMatcher.match("GL_ARB_framebuffer_object")) { + extensions |= QOpenGLExtensions::FramebufferMultisample | + QOpenGLExtensions::FramebufferBlit | + QOpenGLExtensions::PackedDepthStencil; + } else { + if (extensionMatcher.match("GL_EXT_framebuffer_multisample")) + extensions |= QOpenGLExtensions::FramebufferMultisample; + if (extensionMatcher.match("GL_EXT_framebuffer_blit")) + extensions |= QOpenGLExtensions::FramebufferBlit; + if (extensionMatcher.match("GL_EXT_pakced_depth_stencil")) + extensions |= QOpenGLExtensions::PackedDepthStencil; + } +#endif + return extensions; +} + +/*! + Returns the set of features that are present on this system's + OpenGL implementation. + + It is assumed that the QOpenGLContext associated with this function + resolver is current. + + \sa hasOpenGLFeature() +*/ +QOpenGLFunctions::OpenGLFeatures QOpenGLFunctions::openGLFeatures() const +{ + QOpenGLFunctionsPrivateEx *d = static_cast(d_ptr); + if (!d) + return 0; + if (d->m_features == -1) + d->m_features = qt_gl_resolve_features(); + return QOpenGLFunctions::OpenGLFeatures(d->m_features); +} + +/*! + Returns true if \a feature is present on this system's OpenGL + implementation; false otherwise. + + It is assumed that the QOpenGLContext associated with this function + resolver is current. + + \sa openGLFeatures() +*/ +bool QOpenGLFunctions::hasOpenGLFeature(QOpenGLFunctions::OpenGLFeature feature) const +{ + QOpenGLFunctionsPrivateEx *d = static_cast(d_ptr); + if (!d) + return false; + if (d->m_features == -1) + d->m_features = qt_gl_resolve_features(); + return (d->m_features & int(feature)) != 0; +} + +/*! + Returns the set of extensions that are present on this system's + OpenGL implementation. + + It is assumed that the QOpenGLContext associated with this extension + resolver is current. + + \sa hasOpenGLExtensions() +*/ +QOpenGLExtensions::OpenGLExtensions QOpenGLExtensions::openGLExtensions() +{ + QOpenGLFunctionsPrivateEx *d = static_cast(d_ptr); + if (!d) + return 0; + if (d->m_extensions == -1) + d->m_extensions = qt_gl_resolve_extensions(); + return QOpenGLExtensions::OpenGLExtensions(d->m_extensions); +} + +/*! + Returns true if \a extension is present on this system's OpenGL + implementation; false otherwise. + + It is assumed that the QOpenGLContext associated with this extension + resolver is current. + + \sa openGLFeatures() +*/ +bool QOpenGLExtensions::hasOpenGLExtension(QOpenGLExtensions::OpenGLExtension extension) const +{ + QOpenGLFunctionsPrivateEx *d = static_cast(d_ptr); + if (!d) + return false; + if (d->m_extensions == -1) + d->m_extensions = qt_gl_resolve_extensions(); + return (d->m_extensions & int(extension)) != 0; +} + +/*! + Initializes GL function resolution for the current context. + + After calling this function, the QOpenGLFunctions object can only be + used with the current context and other contexts that share with it. + Call initializeGLFunctions() again to change the object's context + association. +*/ +void QOpenGLFunctions::initializeGLFunctions() +{ + d_ptr = qt_gl_functions(); +} + +/*! + \fn void QOpenGLFunctions::glActiveTexture(GLenum texture) + + Convenience function that calls glActiveTexture(\a texture). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glActiveTexture.xml}{glActiveTexture()}. +*/ + +/*! + \fn void QOpenGLFunctions::glAttachShader(GLuint program, GLuint shader) + + Convenience function that calls glAttachShader(\a program, \a shader). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glAttachShader.xml}{glAttachShader()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glBindAttribLocation(GLuint program, GLuint index, const char* name) + + Convenience function that calls glBindAttribLocation(\a program, \a index, \a name). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glBindAttribLocation.xml}{glBindAttribLocation()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glBindBuffer(GLenum target, GLuint buffer) + + Convenience function that calls glBindBuffer(\a target, \a buffer). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glBindBuffer.xml}{glBindBuffer()}. +*/ + +/*! + \fn void QOpenGLFunctions::glBindFramebuffer(GLenum target, GLuint framebuffer) + + Convenience function that calls glBindFramebuffer(\a target, \a framebuffer). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glBindFramebuffer.xml}{glBindFramebuffer()}. +*/ + +/*! + \fn void QOpenGLFunctions::glBindRenderbuffer(GLenum target, GLuint renderbuffer) + + Convenience function that calls glBindRenderbuffer(\a target, \a renderbuffer). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glBindRenderbuffer.xml}{glBindRenderbuffer()}. +*/ + +/*! + \fn void QOpenGLFunctions::glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) + + Convenience function that calls glBlendColor(\a red, \a green, \a blue, \a alpha). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glBlendColor.xml}{glBlendColor()}. +*/ + +/*! + \fn void QOpenGLFunctions::glBlendEquation(GLenum mode) + + Convenience function that calls glBlendEquation(\a mode). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glBlendEquation.xml}{glBlendEquation()}. +*/ + +/*! + \fn void QOpenGLFunctions::glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) + + Convenience function that calls glBlendEquationSeparate(\a modeRGB, \a modeAlpha). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glBlendEquationSeparate.xml}{glBlendEquationSeparate()}. +*/ + +/*! + \fn void QOpenGLFunctions::glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) + + Convenience function that calls glBlendFuncSeparate(\a srcRGB, \a dstRGB, \a srcAlpha, \a dstAlpha). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glBlendFuncSeparate.xml}{glBlendFuncSeparate()}. +*/ + +/*! + \fn void QOpenGLFunctions::glBufferData(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage) + + Convenience function that calls glBufferData(\a target, \a size, \a data, \a usage). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glBufferData.xml}{glBufferData()}. +*/ + +/*! + \fn void QOpenGLFunctions::glBufferSubData(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data) + + Convenience function that calls glBufferSubData(\a target, \a offset, \a size, \a data). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glBufferSubData.xml}{glBufferSubData()}. +*/ + +/*! + \fn GLenum QOpenGLFunctions::glCheckFramebufferStatus(GLenum target) + + Convenience function that calls glCheckFramebufferStatus(\a target). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glCheckFramebufferStatus.xml}{glCheckFramebufferStatus()}. +*/ + +/*! + \fn void QOpenGLFunctions::glClearDepthf(GLclampf depth) + + Convenience function that calls glClearDepth(\a depth) on + desktop OpenGL systems and glClearDepthf(\a depth) on + embedded OpenGL/ES systems. + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glClearDepthf.xml}{glClearDepthf()}. +*/ + +/*! + \fn void QOpenGLFunctions::glCompileShader(GLuint shader) + + Convenience function that calls glCompileShader(\a shader). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glCompileShader.xml}{glCompileShader()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data) + + Convenience function that calls glCompressedTexImage2D(\a target, \a level, \a internalformat, \a width, \a height, \a border, \a imageSize, \a data). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glCompressedTexImage2D.xml}{glCompressedTexImage2D()}. +*/ + +/*! + \fn void QOpenGLFunctions::glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) + + Convenience function that calls glCompressedTexSubImage2D(\a target, \a level, \a xoffset, \a yoffset, \a width, \a height, \a format, \a imageSize, \a data). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glCompressedTexSubImage2D.xml}{glCompressedTexSubImage2D()}. +*/ + +/*! + \fn GLuint QOpenGLFunctions::glCreateProgram() + + Convenience function that calls glCreateProgram(). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glCreateProgram.xml}{glCreateProgram()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn GLuint QOpenGLFunctions::glCreateShader(GLenum type) + + Convenience function that calls glCreateShader(\a type). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glCreateShader.xml}{glCreateShader()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glDeleteBuffers(GLsizei n, const GLuint* buffers) + + Convenience function that calls glDeleteBuffers(\a n, \a buffers). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glDeleteBuffers.xml}{glDeleteBuffers()}. +*/ + +/*! + \fn void QOpenGLFunctions::glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) + + Convenience function that calls glDeleteFramebuffers(\a n, \a framebuffers). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glDeleteFramebuffers.xml}{glDeleteFramebuffers()}. +*/ + +/*! + \fn void QOpenGLFunctions::glDeleteProgram(GLuint program) + + Convenience function that calls glDeleteProgram(\a program). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glDeleteProgram.xml}{glDeleteProgram()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) + + Convenience function that calls glDeleteRenderbuffers(\a n, \a renderbuffers). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glDeleteRenderbuffers.xml}{glDeleteRenderbuffers()}. +*/ + +/*! + \fn void QOpenGLFunctions::glDeleteShader(GLuint shader) + + Convenience function that calls glDeleteShader(\a shader). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glDeleteShader.xml}{glDeleteShader()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glDepthRangef(GLclampf zNear, GLclampf zFar) + + Convenience function that calls glDepthRange(\a zNear, \a zFar) on + desktop OpenGL systems and glDepthRangef(\a zNear, \a zFar) on + embedded OpenGL/ES systems. + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glDepthRangef.xml}{glDepthRangef()}. +*/ + +/*! + \fn void QOpenGLFunctions::glDetachShader(GLuint program, GLuint shader) + + Convenience function that calls glDetachShader(\a program, \a shader). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glDetachShader.xml}{glDetachShader()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glDisableVertexAttribArray(GLuint index) + + Convenience function that calls glDisableVertexAttribArray(\a index). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glDisableVertexAttribArray.xml}{glDisableVertexAttribArray()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glEnableVertexAttribArray(GLuint index) + + Convenience function that calls glEnableVertexAttribArray(\a index). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glEnableVertexAttribArray.xml}{glEnableVertexAttribArray()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) + + Convenience function that calls glFramebufferRenderbuffer(\a target, \a attachment, \a renderbuffertarget, \a renderbuffer). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glFramebufferRenderbuffer.xml}{glFramebufferRenderbuffer()}. +*/ + +/*! + \fn void QOpenGLFunctions::glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) + + Convenience function that calls glFramebufferTexture2D(\a target, \a attachment, \a textarget, \a texture, \a level). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glFramebufferTexture2D.xml}{glFramebufferTexture2D()}. +*/ + +/*! + \fn void QOpenGLFunctions::glGenBuffers(GLsizei n, GLuint* buffers) + + Convenience function that calls glGenBuffers(\a n, \a buffers). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGenBuffers.xml}{glGenBuffers()}. +*/ + +/*! + \fn void QOpenGLFunctions::glGenerateMipmap(GLenum target) + + Convenience function that calls glGenerateMipmap(\a target). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGenerateMipmap.xml}{glGenerateMipmap()}. +*/ + +/*! + \fn void QOpenGLFunctions::glGenFramebuffers(GLsizei n, GLuint* framebuffers) + + Convenience function that calls glGenFramebuffers(\a n, \a framebuffers). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGenFramebuffers.xml}{glGenFramebuffers()}. +*/ + +/*! + \fn void QOpenGLFunctions::glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) + + Convenience function that calls glGenRenderbuffers(\a n, \a renderbuffers). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGenRenderbuffers.xml}{glGenRenderbuffers()}. +*/ + +/*! + \fn void QOpenGLFunctions::glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) + + Convenience function that calls glGetActiveAttrib(\a program, \a index, \a bufsize, \a length, \a size, \a type, \a name). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetActiveAttrib.xml}{glGetActiveAttrib()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) + + Convenience function that calls glGetActiveUniform(\a program, \a index, \a bufsize, \a length, \a size, \a type, \a name). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetActiveUniform.xml}{glGetActiveUniform()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) + + Convenience function that calls glGetAttachedShaders(\a program, \a maxcount, \a count, \a shaders). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetAttachedShaders.xml}{glGetAttachedShaders()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn GLint QOpenGLFunctions::glGetAttribLocation(GLuint program, const char* name) + + Convenience function that calls glGetAttribLocation(\a program, \a name). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetAttribLocation.xml}{glGetAttribLocation()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) + + Convenience function that calls glGetBufferParameteriv(\a target, \a pname, \a params). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetBufferParameteriv.xml}{glGetBufferParameteriv()}. +*/ + +/*! + \fn void QOpenGLFunctions::glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) + + Convenience function that calls glGetFramebufferAttachmentParameteriv(\a target, \a attachment, \a pname, \a params). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetFramebufferAttachmentParameteriv.xml}{glGetFramebufferAttachmentParameteriv()}. +*/ + +/*! + \fn void QOpenGLFunctions::glGetProgramiv(GLuint program, GLenum pname, GLint* params) + + Convenience function that calls glGetProgramiv(\a program, \a pname, \a params). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetProgramiv.xml}{glGetProgramiv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) + + Convenience function that calls glGetProgramInfoLog(\a program, \a bufsize, \a length, \a infolog). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetProgramInfoLog.xml}{glGetProgramInfoLog()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) + + Convenience function that calls glGetRenderbufferParameteriv(\a target, \a pname, \a params). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetRenderbufferParameteriv.xml}{glGetRenderbufferParameteriv()}. +*/ + +/*! + \fn void QOpenGLFunctions::glGetShaderiv(GLuint shader, GLenum pname, GLint* params) + + Convenience function that calls glGetShaderiv(\a shader, \a pname, \a params). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetShaderiv.xml}{glGetShaderiv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) + + Convenience function that calls glGetShaderInfoLog(\a shader, \a bufsize, \a length, \a infolog). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetShaderInfoLog.xml}{glGetShaderInfoLog()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) + + Convenience function that calls glGetShaderPrecisionFormat(\a shadertype, \a precisiontype, \a range, \a precision). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetShaderPrecisionFormat.xml}{glGetShaderPrecisionFormat()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source) + + Convenience function that calls glGetShaderSource(\a shader, \a bufsize, \a length, \a source). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetShaderSource.xml}{glGetShaderSource()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetUniformfv(GLuint program, GLint location, GLfloat* params) + + Convenience function that calls glGetUniformfv(\a program, \a location, \a params). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetUniformfv.xml}{glGetUniformfv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetUniformiv(GLuint program, GLint location, GLint* params) + + Convenience function that calls glGetUniformiv(\a program, \a location, \a params). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetUniformiv.xml}{glGetUniformiv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn GLint QOpenGLFunctions::glGetUniformLocation(GLuint program, const char* name) + + Convenience function that calls glGetUniformLocation(\a program, \a name). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetUniformLocation.xml}{glGetUniformLocation()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) + + Convenience function that calls glGetVertexAttribfv(\a index, \a pname, \a params). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetVertexAttribfv.xml}{glGetVertexAttribfv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) + + Convenience function that calls glGetVertexAttribiv(\a index, \a pname, \a params). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetVertexAttribiv.xml}{glGetVertexAttribiv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer) + + Convenience function that calls glGetVertexAttribPointerv(\a index, \a pname, \a pointer). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glGetVertexAttribPointerv.xml}{glGetVertexAttribPointerv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn GLboolean QOpenGLFunctions::glIsBuffer(GLuint buffer) + + Convenience function that calls glIsBuffer(\a buffer). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glIsBuffer.xml}{glIsBuffer()}. +*/ + +/*! + \fn GLboolean QOpenGLFunctions::glIsFramebuffer(GLuint framebuffer) + + Convenience function that calls glIsFramebuffer(\a framebuffer). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glIsFramebuffer.xml}{glIsFramebuffer()}. +*/ + +/*! + \fn GLboolean QOpenGLFunctions::glIsProgram(GLuint program) + + Convenience function that calls glIsProgram(\a program). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glIsProgram.xml}{glIsProgram()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn GLboolean QOpenGLFunctions::glIsRenderbuffer(GLuint renderbuffer) + + Convenience function that calls glIsRenderbuffer(\a renderbuffer). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glIsRenderbuffer.xml}{glIsRenderbuffer()}. +*/ + +/*! + \fn GLboolean QOpenGLFunctions::glIsShader(GLuint shader) + + Convenience function that calls glIsShader(\a shader). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glIsShader.xml}{glIsShader()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glLinkProgram(GLuint program) + + Convenience function that calls glLinkProgram(\a program). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glLinkProgram.xml}{glLinkProgram()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glReleaseShaderCompiler() + + Convenience function that calls glReleaseShaderCompiler(). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glReleaseShaderCompiler.xml}{glReleaseShaderCompiler()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) + + Convenience function that calls glRenderbufferStorage(\a target, \a internalformat, \a width, \a height). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glRenderbufferStorage.xml}{glRenderbufferStorage()}. +*/ + +/*! + \fn void QOpenGLFunctions::glSampleCoverage(GLclampf value, GLboolean invert) + + Convenience function that calls glSampleCoverage(\a value, \a invert). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glSampleCoverage.xml}{glSampleCoverage()}. +*/ + +/*! + \fn void QOpenGLFunctions::glShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length) + + Convenience function that calls glShaderBinary(\a n, \a shaders, \a binaryformat, \a binary, \a length). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glShaderBinary.xml}{glShaderBinary()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length) + + Convenience function that calls glShaderSource(\a shader, \a count, \a string, \a length). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glShaderSource.xml}{glShaderSource()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) + + Convenience function that calls glStencilFuncSeparate(\a face, \a func, \a ref, \a mask). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glStencilFuncSeparate.xml}{glStencilFuncSeparate()}. +*/ + +/*! + \fn void QOpenGLFunctions::glStencilMaskSeparate(GLenum face, GLuint mask) + + Convenience function that calls glStencilMaskSeparate(\a face, \a mask). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glStencilMaskSeparate.xml}{glStencilMaskSeparate()}. +*/ + +/*! + \fn void QOpenGLFunctions::glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) + + Convenience function that calls glStencilOpSeparate(\a face, \a fail, \a zfail, \a zpass). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glStencilOpSeparate.xml}{glStencilOpSeparate()}. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform1f(GLint location, GLfloat x) + + Convenience function that calls glUniform1f(\a location, \a x). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform1f.xml}{glUniform1f()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform1fv(GLint location, GLsizei count, const GLfloat* v) + + Convenience function that calls glUniform1fv(\a location, \a count, \a v). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform1fv.xml}{glUniform1fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform1i(GLint location, GLint x) + + Convenience function that calls glUniform1i(\a location, \a x). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform1i.xml}{glUniform1i()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform1iv(GLint location, GLsizei count, const GLint* v) + + Convenience function that calls glUniform1iv(\a location, \a count, \a v). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform1iv.xml}{glUniform1iv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform2f(GLint location, GLfloat x, GLfloat y) + + Convenience function that calls glUniform2f(\a location, \a x, \a y). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform2f.xml}{glUniform2f()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform2fv(GLint location, GLsizei count, const GLfloat* v) + + Convenience function that calls glUniform2fv(\a location, \a count, \a v). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform2fv.xml}{glUniform2fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform2i(GLint location, GLint x, GLint y) + + Convenience function that calls glUniform2i(\a location, \a x, \a y). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform2i.xml}{glUniform2i()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform2iv(GLint location, GLsizei count, const GLint* v) + + Convenience function that calls glUniform2iv(\a location, \a count, \a v). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform2iv.xml}{glUniform2iv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) + + Convenience function that calls glUniform3f(\a location, \a x, \a y, \a z). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform3f.xml}{glUniform3f()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform3fv(GLint location, GLsizei count, const GLfloat* v) + + Convenience function that calls glUniform3fv(\a location, \a count, \a v). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform3fv.xml}{glUniform3fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform3i(GLint location, GLint x, GLint y, GLint z) + + Convenience function that calls glUniform3i(\a location, \a x, \a y, \a z). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform3i.xml}{glUniform3i()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform3iv(GLint location, GLsizei count, const GLint* v) + + Convenience function that calls glUniform3iv(\a location, \a count, \a v). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform3iv.xml}{glUniform3iv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) + + Convenience function that calls glUniform4f(\a location, \a x, \a y, \a z, \a w). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform4f.xml}{glUniform4f()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform4fv(GLint location, GLsizei count, const GLfloat* v) + + Convenience function that calls glUniform4fv(\a location, \a count, \a v). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform4fv.xml}{glUniform4fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) + + Convenience function that calls glUniform4i(\a location, \a x, \a y, \a z, \a w). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform4i.xml}{glUniform4i()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniform4iv(GLint location, GLsizei count, const GLint* v) + + Convenience function that calls glUniform4iv(\a location, \a count, \a v). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniform4iv.xml}{glUniform4iv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) + + Convenience function that calls glUniformMatrix2fv(\a location, \a count, \a transpose, \a value). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniformMatrix2fv.xml}{glUniformMatrix2fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) + + Convenience function that calls glUniformMatrix3fv(\a location, \a count, \a transpose, \a value). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniformMatrix3fv.xml}{glUniformMatrix3fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) + + Convenience function that calls glUniformMatrix4fv(\a location, \a count, \a transpose, \a value). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUniformMatrix4fv.xml}{glUniformMatrix4fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glUseProgram(GLuint program) + + Convenience function that calls glUseProgram(\a program). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glUseProgram.xml}{glUseProgram()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glValidateProgram(GLuint program) + + Convenience function that calls glValidateProgram(\a program). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glValidateProgram.xml}{glValidateProgram()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glVertexAttrib1f(GLuint indx, GLfloat x) + + Convenience function that calls glVertexAttrib1f(\a indx, \a x). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib1f.xml}{glVertexAttrib1f()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glVertexAttrib1fv(GLuint indx, const GLfloat* values) + + Convenience function that calls glVertexAttrib1fv(\a indx, \a values). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib1fv.xml}{glVertexAttrib1fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) + + Convenience function that calls glVertexAttrib2f(\a indx, \a x, \a y). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib2f.xml}{glVertexAttrib2f()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glVertexAttrib2fv(GLuint indx, const GLfloat* values) + + Convenience function that calls glVertexAttrib2fv(\a indx, \a values). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib2fv.xml}{glVertexAttrib2fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) + + Convenience function that calls glVertexAttrib3f(\a indx, \a x, \a y, \a z). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib3f.xml}{glVertexAttrib3f()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glVertexAttrib3fv(GLuint indx, const GLfloat* values) + + Convenience function that calls glVertexAttrib3fv(\a indx, \a values). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib3fv.xml}{glVertexAttrib3fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) + + Convenience function that calls glVertexAttrib4f(\a indx, \a x, \a y, \a z, \a w). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib4f.xml}{glVertexAttrib4f()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glVertexAttrib4fv(GLuint indx, const GLfloat* values) + + Convenience function that calls glVertexAttrib4fv(\a indx, \a values). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttrib4fv.xml}{glVertexAttrib4fv()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +/*! + \fn void QOpenGLFunctions::glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr) + + Convenience function that calls glVertexAttribPointer(\a indx, \a size, \a type, \a normalized, \a stride, \a ptr). + + For more information, see the OpenGL/ES 2.0 documentation for + \l{http://www.khronos.org/opengles/sdk/docs/man/glVertexAttribPointer.xml}{glVertexAttribPointer()}. + + This convenience function will do nothing on OpenGL/ES 1.x systems. +*/ + +namespace { + +enum ResolvePolicy +{ + ResolveOES = 0x1, + ResolveEXT = 0x2 +}; + +template +class Resolver +{ +public: + Resolver(FuncType Base::*func, FuncType fallback, const char *name, const char *alternateName = 0) + : funcPointerName(func) + , fallbackFuncPointer(fallback) + , funcName(name) + , alternateFuncName(alternateName) + { + } + + ReturnType operator()(); + + template + ReturnType operator()(P1 p1); + + template + ReturnType operator()(P1 p1, P2 p2); + + template + ReturnType operator()(P1 p1, P2 p2, P3 p3); + + template + ReturnType operator()(P1 p1, P2 p2, P3 p3, P4 p4); + + template + ReturnType operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5); + + template + ReturnType operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6); + + template + ReturnType operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7); + + template + ReturnType operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8); + + template + ReturnType operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9); + + template + ReturnType operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10); + +private: + FuncType Base::*funcPointerName; + FuncType fallbackFuncPointer; + QByteArray funcName; + QByteArray alternateFuncName; +}; + +template +class Resolver +{ +public: + Resolver(FuncType Base::*func, FuncType fallback, const char *name, const char *alternateName = 0) + : funcPointerName(func) + , fallbackFuncPointer(fallback) + , funcName(name) + , alternateFuncName(alternateName) + { + } + + void operator()(); + + template + void operator()(P1 p1); + + template + void operator()(P1 p1, P2 p2); + + template + void operator()(P1 p1, P2 p2, P3 p3); + + template + void operator()(P1 p1, P2 p2, P3 p3, P4 p4); + + template + void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5); + + template + void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6); + + template + void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7); + + template + void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8); + + template + void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9); + + template + void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10); + +private: + FuncType Base::*funcPointerName; + FuncType fallbackFuncPointer; + QByteArray funcName; + QByteArray alternateFuncName; +}; + +#define RESOLVER_COMMON \ + QOpenGLContext *context = QOpenGLContext::currentContext(); \ + Base *funcs = qt_gl_functions(context); \ + \ + FuncType old = funcs->*funcPointerName; \ + \ + funcs->*funcPointerName = (FuncType)context->getProcAddress(funcName); \ + \ + if ((Policy & ResolveOES) && !(funcs->*funcPointerName)) \ + funcs->*funcPointerName = (FuncType)context->getProcAddress(funcName + "OES"); \ + \ + if (!(funcs->*funcPointerName)) \ + funcs->*funcPointerName = (FuncType)context->getProcAddress(funcName + "ARB"); \ + \ + if ((Policy & ResolveEXT) && !(funcs->*funcPointerName)) \ + funcs->*funcPointerName = (FuncType)context->getProcAddress(funcName + "EXT"); \ + \ + if (!alternateFuncName.isEmpty() && !(funcs->*funcPointerName)) { \ + funcs->*funcPointerName = (FuncType)context->getProcAddress(alternateFuncName); \ + \ + if ((Policy & ResolveOES) && !(funcs->*funcPointerName)) \ + funcs->*funcPointerName = (FuncType)context->getProcAddress(alternateFuncName + "OES"); \ + \ + if (!(funcs->*funcPointerName)) \ + funcs->*funcPointerName = (FuncType)context->getProcAddress(alternateFuncName + "ARB"); \ + \ + if ((Policy & ResolveEXT) && !(funcs->*funcPointerName)) \ + funcs->*funcPointerName = (FuncType)context->getProcAddress(alternateFuncName + "EXT"); \ + } + +#define RESOLVER_COMMON_NON_VOID \ + RESOLVER_COMMON \ + \ + if (!(funcs->*funcPointerName)) { \ + if (fallbackFuncPointer) { \ + funcs->*funcPointerName = fallbackFuncPointer; \ + } else { \ + funcs->*funcPointerName = old; \ + return ReturnType(); \ + } \ + } + +#define RESOLVER_COMMON_VOID \ + RESOLVER_COMMON \ + \ + if (!(funcs->*funcPointerName)) { \ + if (fallbackFuncPointer) { \ + funcs->*funcPointerName = fallbackFuncPointer; \ + } else { \ + funcs->*funcPointerName = old; \ + return; \ + } \ + } + +template +ReturnType Resolver::operator()() +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(); +} + +template template +ReturnType Resolver::operator()(P1 p1) +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(p1); +} + +template template +ReturnType Resolver::operator()(P1 p1, P2 p2) +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(p1, p2); +} + +template template +ReturnType Resolver::operator()(P1 p1, P2 p2, P3 p3) +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(p1, p2, p3); +} + +template template +ReturnType Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4) +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(p1, p2, p3, p4); +} + +template template +ReturnType Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(p1, p2, p3, p4, p5); +} + +template template +ReturnType Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(p1, p2, p3, p4, p5, p6); +} + +template template +ReturnType Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(p1, p2, p3, p4, p5, p6, p7); +} + +template template +ReturnType Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(p1, p2, p3, p4, p5, p6, p7, p8); +} + +template template +ReturnType Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(p1, p2, p3, p4, p5, p6, p7, p8, p9); +} + +template template +ReturnType Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10) +{ + RESOLVER_COMMON_NON_VOID + + return (funcs->*funcPointerName)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +} + +template +void Resolver::operator()() +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(); +} + +template template +void Resolver::operator()(P1 p1) +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(p1); +} + +template template +void Resolver::operator()(P1 p1, P2 p2) +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(p1, p2); +} + +template template +void Resolver::operator()(P1 p1, P2 p2, P3 p3) +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(p1, p2, p3); +} + +template template +void Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4) +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(p1, p2, p3, p4); +} + +template template +void Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(p1, p2, p3, p4, p5); +} + +template template +void Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(p1, p2, p3, p4, p5, p6); +} + +template template +void Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(p1, p2, p3, p4, p5, p6, p7); +} + +template template +void Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(p1, p2, p3, p4, p5, p6, p7, p8); +} + +template template +void Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(p1, p2, p3, p4, p5, p6, p7, p8, p9); +} + +template template +void Resolver::operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10) +{ + RESOLVER_COMMON_VOID + + (funcs->*funcPointerName)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +} + +template +Resolver functionResolverWithFallback(FuncType Base::*func, FuncType fallback, const char *name, const char *alternate = 0) +{ + return Resolver(func, fallback, name, alternate); +} + +template +Resolver functionResolver(FuncType Base::*func, const char *name, const char *alternate = 0) +{ + return Resolver(func, 0, name, alternate); +} + +} + +#define RESOLVE_FUNC(RETURN_TYPE, POLICY, NAME) \ + return functionResolver(&QOpenGLExtensionsPrivate::NAME, "gl" #NAME) + +#define RESOLVE_FUNC_VOID(POLICY, NAME) \ + functionResolver(&QOpenGLExtensionsPrivate::NAME, "gl" #NAME) + +#define RESOLVE_FUNC_SPECIAL(RETURN_TYPE, POLICY, NAME) \ + return functionResolverWithFallback(&QOpenGLExtensionsPrivate::NAME, qopenglfSpecial##NAME, "gl" #NAME) + +#define RESOLVE_FUNC_SPECIAL_VOID(POLICY, NAME) \ + functionResolverWithFallback(&QOpenGLExtensionsPrivate::NAME, qopenglfSpecial##NAME, "gl" #NAME) + +#define RESOLVE_FUNC_WITH_ALTERNATE(RETURN_TYPE, POLICY, NAME, ALTERNATE) \ + return functionResolver(&QOpenGLExtensionsPrivate::NAME, "gl" #NAME, "gl" #ALTERNATE) + +#define RESOLVE_FUNC_VOID_WITH_ALTERNATE(POLICY, NAME, ALTERNATE) \ + functionResolver(&QOpenGLExtensionsPrivate::NAME, "gl" #NAME, "gl" #ALTERNATE) + +#ifndef QT_OPENGL_ES_2 + +static void QOPENGLF_APIENTRY qopenglfResolveActiveTexture(GLenum texture) +{ + RESOLVE_FUNC_VOID(0, ActiveTexture)(texture); +} + +static void QOPENGLF_APIENTRY qopenglfResolveAttachShader(GLuint program, GLuint shader) +{ + RESOLVE_FUNC_VOID_WITH_ALTERNATE(0, AttachShader, AttachObject)(program, shader); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBindAttribLocation(GLuint program, GLuint index, const char* name) +{ + RESOLVE_FUNC_VOID(0, BindAttribLocation)(program, index, name); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBindBuffer(GLenum target, GLuint buffer) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, BindBuffer)(target, buffer); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBindFramebuffer(GLenum target, GLuint framebuffer) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, BindFramebuffer)(target, framebuffer); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, BindRenderbuffer)(target, renderbuffer); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, BlendColor)(red, green, blue, alpha); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBlendEquation(GLenum mode) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, BlendEquation)(mode); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, BlendEquationSeparate)(modeRGB, modeAlpha); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, BlendFuncSeparate)(srcRGB, dstRGB, srcAlpha, dstAlpha); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBufferData(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, BufferData)(target, size, data, usage); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBufferSubData(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, BufferSubData)(target, offset, size, data); +} + +static GLenum QOPENGLF_APIENTRY qopenglfResolveCheckFramebufferStatus(GLenum target) +{ + RESOLVE_FUNC(GLenum, ResolveOES | ResolveEXT, CheckFramebufferStatus)(target); +} + +static void QOPENGLF_APIENTRY qopenglfResolveCompileShader(GLuint shader) +{ + RESOLVE_FUNC_VOID(0, CompileShader)(shader); +} + +static void QOPENGLF_APIENTRY qopenglfResolveCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, CompressedTexImage2D)(target, level, internalformat, width, height, border, imageSize, data); +} + +static void QOPENGLF_APIENTRY qopenglfResolveCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, CompressedTexSubImage2D)(target, level, xoffset, yoffset, width, height, format, imageSize, data); +} + +static GLuint QOPENGLF_APIENTRY qopenglfResolveCreateProgram() +{ + RESOLVE_FUNC_WITH_ALTERNATE(GLuint, 0, CreateProgram, CreateProgramObject)(); +} + +static GLuint QOPENGLF_APIENTRY qopenglfResolveCreateShader(GLenum type) +{ + RESOLVE_FUNC_WITH_ALTERNATE(GLuint, 0, CreateShader, CreateShaderObject)(type); +} + +static void QOPENGLF_APIENTRY qopenglfResolveDeleteBuffers(GLsizei n, const GLuint* buffers) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, DeleteBuffers)(n, buffers); +} + +static void QOPENGLF_APIENTRY qopenglfResolveDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, DeleteFramebuffers)(n, framebuffers); +} + +static void QOPENGLF_APIENTRY qopenglfResolveDeleteProgram(GLuint program) +{ + RESOLVE_FUNC_VOID(0, DeleteProgram)(program); +} + +static void QOPENGLF_APIENTRY qopenglfResolveDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, DeleteRenderbuffers)(n, renderbuffers); +} + +static void QOPENGLF_APIENTRY qopenglfResolveDeleteShader(GLuint shader) +{ + RESOLVE_FUNC_VOID_WITH_ALTERNATE(0, DeleteShader, DeleteObject)(shader); +} + +static void QOPENGLF_APIENTRY qopenglfResolveDetachShader(GLuint program, GLuint shader) +{ + RESOLVE_FUNC_VOID_WITH_ALTERNATE(0, DetachShader, DetachObject)(program, shader); +} + +static void QOPENGLF_APIENTRY qopenglfResolveDisableVertexAttribArray(GLuint index) +{ + RESOLVE_FUNC_VOID(0, DisableVertexAttribArray)(index); +} + +static void QOPENGLF_APIENTRY qopenglfResolveEnableVertexAttribArray(GLuint index) +{ + RESOLVE_FUNC_VOID(0, EnableVertexAttribArray)(index); +} + +static void QOPENGLF_APIENTRY qopenglfResolveFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, FramebufferRenderbuffer)(target, attachment, renderbuffertarget, renderbuffer); +} + +static void QOPENGLF_APIENTRY qopenglfResolveFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, FramebufferTexture2D)(target, attachment, textarget, texture, level); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGenBuffers(GLsizei n, GLuint* buffers) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, GenBuffers)(n, buffers); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGenerateMipmap(GLenum target) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, GenerateMipmap)(target); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGenFramebuffers(GLsizei n, GLuint* framebuffers) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, GenFramebuffers)(n, framebuffers); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGenRenderbuffers(GLsizei n, GLuint* renderbuffers) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, GenRenderbuffers)(n, renderbuffers); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) +{ + RESOLVE_FUNC_VOID(0, GetActiveAttrib)(program, index, bufsize, length, size, type, name); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) +{ + RESOLVE_FUNC_VOID(0, GetActiveUniform)(program, index, bufsize, length, size, type, name); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +{ + RESOLVE_FUNC_VOID_WITH_ALTERNATE(0, GetAttachedShaders, GetAttachedObjects)(program, maxcount, count, shaders); +} + +static GLint QOPENGLF_APIENTRY qopenglfResolveGetAttribLocation(GLuint program, const char* name) +{ + RESOLVE_FUNC(GLint, 0, GetAttribLocation)(program, name); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, GetBufferParameteriv)(target, pname, params); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, GetFramebufferAttachmentParameteriv)(target, attachment, pname, params); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetProgramiv(GLuint program, GLenum pname, GLint* params) +{ + RESOLVE_FUNC_VOID_WITH_ALTERNATE(0, GetProgramiv, GetObjectParameteriv)(program, pname, params); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) +{ + RESOLVE_FUNC_VOID_WITH_ALTERNATE(0, GetProgramInfoLog, GetInfoLog)(program, bufsize, length, infolog); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, GetRenderbufferParameteriv)(target, pname, params); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetShaderiv(GLuint shader, GLenum pname, GLint* params) +{ + RESOLVE_FUNC_VOID_WITH_ALTERNATE(0, GetShaderiv, GetObjectParameteriv)(shader, pname, params); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) +{ + RESOLVE_FUNC_VOID_WITH_ALTERNATE(0, GetShaderInfoLog, GetInfoLog)(shader, bufsize, length, infolog); +} + +static void QOPENGLF_APIENTRY qopenglfSpecialGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +{ + Q_UNUSED(shadertype); + Q_UNUSED(precisiontype); + range[0] = range[1] = precision[0] = 0; +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +{ + RESOLVE_FUNC_SPECIAL_VOID(ResolveOES | ResolveEXT, GetShaderPrecisionFormat)(shadertype, precisiontype, range, precision); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source) +{ + RESOLVE_FUNC_VOID(0, GetShaderSource)(shader, bufsize, length, source); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetUniformfv(GLuint program, GLint location, GLfloat* params) +{ + RESOLVE_FUNC_VOID(0, GetUniformfv)(program, location, params); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetUniformiv(GLuint program, GLint location, GLint* params) +{ + RESOLVE_FUNC_VOID(0, GetUniformiv)(program, location, params); +} + +static GLint QOPENGLF_APIENTRY qopenglfResolveGetUniformLocation(GLuint program, const char* name) +{ + RESOLVE_FUNC(GLint, 0, GetUniformLocation)(program, name); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) +{ + RESOLVE_FUNC_VOID(0, GetVertexAttribfv)(index, pname, params); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) +{ + RESOLVE_FUNC_VOID(0, GetVertexAttribiv)(index, pname, params); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer) +{ + RESOLVE_FUNC_VOID(0, GetVertexAttribPointerv)(index, pname, pointer); +} + +static GLboolean QOPENGLF_APIENTRY qopenglfResolveIsBuffer(GLuint buffer) +{ + RESOLVE_FUNC(GLboolean, ResolveOES | ResolveEXT, IsBuffer)(buffer); +} + +static GLboolean QOPENGLF_APIENTRY qopenglfResolveIsFramebuffer(GLuint framebuffer) +{ + RESOLVE_FUNC(GLboolean, ResolveOES | ResolveEXT, IsFramebuffer)(framebuffer); +} + +static GLboolean QOPENGLF_APIENTRY qopenglfSpecialIsProgram(GLuint program) +{ + return program != 0; +} + +static GLboolean QOPENGLF_APIENTRY qopenglfResolveIsProgram(GLuint program) +{ + RESOLVE_FUNC_SPECIAL(GLboolean, 0, IsProgram)(program); +} + +static GLboolean QOPENGLF_APIENTRY qopenglfResolveIsRenderbuffer(GLuint renderbuffer) +{ + RESOLVE_FUNC(GLboolean, ResolveOES | ResolveEXT, IsRenderbuffer)(renderbuffer); +} + +static GLboolean QOPENGLF_APIENTRY qopenglfSpecialIsShader(GLuint shader) +{ + return shader != 0; +} + +static GLboolean QOPENGLF_APIENTRY qopenglfResolveIsShader(GLuint shader) +{ + RESOLVE_FUNC_SPECIAL(GLboolean, 0, IsShader)(shader); +} + +static void QOPENGLF_APIENTRY qopenglfResolveLinkProgram(GLuint program) +{ + RESOLVE_FUNC_VOID(0, LinkProgram)(program); +} + +static void QOPENGLF_APIENTRY qopenglfSpecialReleaseShaderCompiler() +{ +} + +static void QOPENGLF_APIENTRY qopenglfResolveReleaseShaderCompiler() +{ + RESOLVE_FUNC_SPECIAL_VOID(0, ReleaseShaderCompiler)(); +} + +static void QOPENGLF_APIENTRY qopenglfResolveRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, RenderbufferStorage)(target, internalformat, width, height); +} + +static void QOPENGLF_APIENTRY qopenglfResolveSampleCoverage(GLclampf value, GLboolean invert) +{ + RESOLVE_FUNC_VOID(ResolveOES | ResolveEXT, SampleCoverage)(value, invert); +} + +static void QOPENGLF_APIENTRY qopenglfResolveShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length) +{ + RESOLVE_FUNC_VOID(0, ShaderBinary)(n, shaders, binaryformat, binary, length); +} + +static void QOPENGLF_APIENTRY qopenglfResolveShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length) +{ + RESOLVE_FUNC_VOID(0, ShaderSource)(shader, count, string, length); +} + +static void QOPENGLF_APIENTRY qopenglfResolveStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + RESOLVE_FUNC_VOID(ResolveEXT, StencilFuncSeparate)(face, func, ref, mask); +} + +static void QOPENGLF_APIENTRY qopenglfResolveStencilMaskSeparate(GLenum face, GLuint mask) +{ + RESOLVE_FUNC_VOID(ResolveEXT, StencilMaskSeparate)(face, mask); +} + +static void QOPENGLF_APIENTRY qopenglfResolveStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + RESOLVE_FUNC_VOID(ResolveEXT, StencilOpSeparate)(face, fail, zfail, zpass); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform1f(GLint location, GLfloat x) +{ + RESOLVE_FUNC_VOID(0, Uniform1f)(location, x); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + RESOLVE_FUNC_VOID(0, Uniform1fv)(location, count, v); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform1i(GLint location, GLint x) +{ + RESOLVE_FUNC_VOID(0, Uniform1i)(location, x); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform1iv(GLint location, GLsizei count, const GLint* v) +{ + RESOLVE_FUNC_VOID(0, Uniform1iv)(location, count, v); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform2f(GLint location, GLfloat x, GLfloat y) +{ + RESOLVE_FUNC_VOID(0, Uniform2f)(location, x, y); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform2fv(GLint location, GLsizei count, const GLfloat* v) +{ + RESOLVE_FUNC_VOID(0, Uniform2fv)(location, count, v); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform2i(GLint location, GLint x, GLint y) +{ + RESOLVE_FUNC_VOID(0, Uniform2i)(location, x, y); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform2iv(GLint location, GLsizei count, const GLint* v) +{ + RESOLVE_FUNC_VOID(0, Uniform2iv)(location, count, v); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + RESOLVE_FUNC_VOID(0, Uniform3f)(location, x, y, z); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform3fv(GLint location, GLsizei count, const GLfloat* v) +{ + RESOLVE_FUNC_VOID(0, Uniform3fv)(location, count, v); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform3i(GLint location, GLint x, GLint y, GLint z) +{ + RESOLVE_FUNC_VOID(0, Uniform3i)(location, x, y, z); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform3iv(GLint location, GLsizei count, const GLint* v) +{ + RESOLVE_FUNC_VOID(0, Uniform3iv)(location, count, v); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + RESOLVE_FUNC_VOID(0, Uniform4f)(location, x, y, z, w); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform4fv(GLint location, GLsizei count, const GLfloat* v) +{ + RESOLVE_FUNC_VOID(0, Uniform4fv)(location, count, v); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + RESOLVE_FUNC_VOID(0, Uniform4i)(location, x, y, z, w); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniform4iv(GLint location, GLsizei count, const GLint* v) +{ + RESOLVE_FUNC_VOID(0, Uniform4iv)(location, count, v); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + RESOLVE_FUNC_VOID(0, UniformMatrix2fv)(location, count, transpose, value); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + RESOLVE_FUNC_VOID(0, UniformMatrix3fv)(location, count, transpose, value); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + RESOLVE_FUNC_VOID(0, UniformMatrix4fv)(location, count, transpose, value); +} + +static void QOPENGLF_APIENTRY qopenglfResolveUseProgram(GLuint program) +{ + RESOLVE_FUNC_VOID(0, UseProgram)(program); +} + +static void QOPENGLF_APIENTRY qopenglfResolveValidateProgram(GLuint program) +{ + RESOLVE_FUNC_VOID(0, ValidateProgram)(program); +} + +static void QOPENGLF_APIENTRY qopenglfResolveVertexAttrib1f(GLuint indx, GLfloat x) +{ + RESOLVE_FUNC_VOID(0, VertexAttrib1f)(indx, x); +} + +static void QOPENGLF_APIENTRY qopenglfResolveVertexAttrib1fv(GLuint indx, const GLfloat* values) +{ + RESOLVE_FUNC_VOID(0, VertexAttrib1fv)(indx, values); +} + +static void QOPENGLF_APIENTRY qopenglfResolveVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) +{ + RESOLVE_FUNC_VOID(0, VertexAttrib2f)(indx, x, y); +} + +static void QOPENGLF_APIENTRY qopenglfResolveVertexAttrib2fv(GLuint indx, const GLfloat* values) +{ + RESOLVE_FUNC_VOID(0, VertexAttrib2fv)(indx, values); +} + +static void QOPENGLF_APIENTRY qopenglfResolveVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) +{ + RESOLVE_FUNC_VOID(0, VertexAttrib3f)(indx, x, y, z); +} + +static void QOPENGLF_APIENTRY qopenglfResolveVertexAttrib3fv(GLuint indx, const GLfloat* values) +{ + RESOLVE_FUNC_VOID(0, VertexAttrib3fv)(indx, values); +} + +static void QOPENGLF_APIENTRY qopenglfResolveVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + RESOLVE_FUNC_VOID(0, VertexAttrib4f)(indx, x, y, z, w); +} + +static void QOPENGLF_APIENTRY qopenglfResolveVertexAttrib4fv(GLuint indx, const GLfloat* values) +{ + RESOLVE_FUNC_VOID(0, VertexAttrib4fv)(indx, values); +} + +static void QOPENGLF_APIENTRY qopenglfResolveVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr) +{ + RESOLVE_FUNC_VOID(0, VertexAttribPointer)(indx, size, type, normalized, stride, ptr); +} + +#endif // !QT_OPENGL_ES_2 + +static GLvoid *QOPENGLF_APIENTRY qopenglfResolveMapBuffer(GLenum target, GLenum access) +{ + RESOLVE_FUNC(GLvoid *, ResolveOES, MapBuffer)(target, access); +} + +static GLboolean QOPENGLF_APIENTRY qopenglfResolveUnmapBuffer(GLenum target) +{ + RESOLVE_FUNC(GLboolean, ResolveOES, UnmapBuffer)(target); +} + +static void QOPENGLF_APIENTRY qopenglfResolveBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + RESOLVE_FUNC_VOID(ResolveEXT, BlitFramebuffer) + (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); +} + +static void QOPENGLF_APIENTRY qopenglfResolveRenderbufferStorageMultisample(GLenum target, GLsizei samples, + GLenum internalFormat, + GLsizei width, GLsizei height) +{ + RESOLVE_FUNC_VOID(ResolveEXT, RenderbufferStorageMultisample) + (target, samples, internalFormat, width, height); +} + +static void QOPENGLF_APIENTRY qopenglfResolveGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) +{ + RESOLVE_FUNC_VOID(ResolveEXT, GetBufferSubData) + (target, offset, size, data); +} + +QOpenGLFunctionsPrivate::QOpenGLFunctionsPrivate(QOpenGLContext *) +{ +#ifndef QT_OPENGL_ES_2 + ActiveTexture = qopenglfResolveActiveTexture; + AttachShader = qopenglfResolveAttachShader; + BindAttribLocation = qopenglfResolveBindAttribLocation; + BindBuffer = qopenglfResolveBindBuffer; + BindFramebuffer = qopenglfResolveBindFramebuffer; + BindRenderbuffer = qopenglfResolveBindRenderbuffer; + BlendColor = qopenglfResolveBlendColor; + BlendEquation = qopenglfResolveBlendEquation; + BlendEquationSeparate = qopenglfResolveBlendEquationSeparate; + BlendFuncSeparate = qopenglfResolveBlendFuncSeparate; + BufferData = qopenglfResolveBufferData; + BufferSubData = qopenglfResolveBufferSubData; + CheckFramebufferStatus = qopenglfResolveCheckFramebufferStatus; + CompileShader = qopenglfResolveCompileShader; + CompressedTexImage2D = qopenglfResolveCompressedTexImage2D; + CompressedTexSubImage2D = qopenglfResolveCompressedTexSubImage2D; + CreateProgram = qopenglfResolveCreateProgram; + CreateShader = qopenglfResolveCreateShader; + DeleteBuffers = qopenglfResolveDeleteBuffers; + DeleteFramebuffers = qopenglfResolveDeleteFramebuffers; + DeleteProgram = qopenglfResolveDeleteProgram; + DeleteRenderbuffers = qopenglfResolveDeleteRenderbuffers; + DeleteShader = qopenglfResolveDeleteShader; + DetachShader = qopenglfResolveDetachShader; + DisableVertexAttribArray = qopenglfResolveDisableVertexAttribArray; + EnableVertexAttribArray = qopenglfResolveEnableVertexAttribArray; + FramebufferRenderbuffer = qopenglfResolveFramebufferRenderbuffer; + FramebufferTexture2D = qopenglfResolveFramebufferTexture2D; + GenBuffers = qopenglfResolveGenBuffers; + GenerateMipmap = qopenglfResolveGenerateMipmap; + GenFramebuffers = qopenglfResolveGenFramebuffers; + GenRenderbuffers = qopenglfResolveGenRenderbuffers; + GetActiveAttrib = qopenglfResolveGetActiveAttrib; + GetActiveUniform = qopenglfResolveGetActiveUniform; + GetAttachedShaders = qopenglfResolveGetAttachedShaders; + GetAttribLocation = qopenglfResolveGetAttribLocation; + GetBufferParameteriv = qopenglfResolveGetBufferParameteriv; + GetFramebufferAttachmentParameteriv = qopenglfResolveGetFramebufferAttachmentParameteriv; + GetProgramiv = qopenglfResolveGetProgramiv; + GetProgramInfoLog = qopenglfResolveGetProgramInfoLog; + GetRenderbufferParameteriv = qopenglfResolveGetRenderbufferParameteriv; + GetShaderiv = qopenglfResolveGetShaderiv; + GetShaderInfoLog = qopenglfResolveGetShaderInfoLog; + GetShaderPrecisionFormat = qopenglfResolveGetShaderPrecisionFormat; + GetShaderSource = qopenglfResolveGetShaderSource; + GetUniformfv = qopenglfResolveGetUniformfv; + GetUniformiv = qopenglfResolveGetUniformiv; + GetUniformLocation = qopenglfResolveGetUniformLocation; + GetVertexAttribfv = qopenglfResolveGetVertexAttribfv; + GetVertexAttribiv = qopenglfResolveGetVertexAttribiv; + GetVertexAttribPointerv = qopenglfResolveGetVertexAttribPointerv; + IsBuffer = qopenglfResolveIsBuffer; + IsFramebuffer = qopenglfResolveIsFramebuffer; + IsProgram = qopenglfResolveIsProgram; + IsRenderbuffer = qopenglfResolveIsRenderbuffer; + IsShader = qopenglfResolveIsShader; + LinkProgram = qopenglfResolveLinkProgram; + ReleaseShaderCompiler = qopenglfResolveReleaseShaderCompiler; + RenderbufferStorage = qopenglfResolveRenderbufferStorage; + SampleCoverage = qopenglfResolveSampleCoverage; + ShaderBinary = qopenglfResolveShaderBinary; + ShaderSource = qopenglfResolveShaderSource; + StencilFuncSeparate = qopenglfResolveStencilFuncSeparate; + StencilMaskSeparate = qopenglfResolveStencilMaskSeparate; + StencilOpSeparate = qopenglfResolveStencilOpSeparate; + Uniform1f = qopenglfResolveUniform1f; + Uniform1fv = qopenglfResolveUniform1fv; + Uniform1i = qopenglfResolveUniform1i; + Uniform1iv = qopenglfResolveUniform1iv; + Uniform2f = qopenglfResolveUniform2f; + Uniform2fv = qopenglfResolveUniform2fv; + Uniform2i = qopenglfResolveUniform2i; + Uniform2iv = qopenglfResolveUniform2iv; + Uniform3f = qopenglfResolveUniform3f; + Uniform3fv = qopenglfResolveUniform3fv; + Uniform3i = qopenglfResolveUniform3i; + Uniform3iv = qopenglfResolveUniform3iv; + Uniform4f = qopenglfResolveUniform4f; + Uniform4fv = qopenglfResolveUniform4fv; + Uniform4i = qopenglfResolveUniform4i; + Uniform4iv = qopenglfResolveUniform4iv; + UniformMatrix2fv = qopenglfResolveUniformMatrix2fv; + UniformMatrix3fv = qopenglfResolveUniformMatrix3fv; + UniformMatrix4fv = qopenglfResolveUniformMatrix4fv; + UseProgram = qopenglfResolveUseProgram; + ValidateProgram = qopenglfResolveValidateProgram; + VertexAttrib1f = qopenglfResolveVertexAttrib1f; + VertexAttrib1fv = qopenglfResolveVertexAttrib1fv; + VertexAttrib2f = qopenglfResolveVertexAttrib2f; + VertexAttrib2fv = qopenglfResolveVertexAttrib2fv; + VertexAttrib3f = qopenglfResolveVertexAttrib3f; + VertexAttrib3fv = qopenglfResolveVertexAttrib3fv; + VertexAttrib4f = qopenglfResolveVertexAttrib4f; + VertexAttrib4fv = qopenglfResolveVertexAttrib4fv; + VertexAttribPointer = qopenglfResolveVertexAttribPointer; +#endif // !QT_OPENGL_ES_2 +} + +QOpenGLExtensionsPrivate::QOpenGLExtensionsPrivate(QOpenGLContext *ctx) + : QOpenGLFunctionsPrivate(ctx) +{ + MapBuffer = qopenglfResolveMapBuffer; + UnmapBuffer = qopenglfResolveUnmapBuffer; + BlitFramebuffer = qopenglfResolveBlitFramebuffer; + RenderbufferStorageMultisample = qopenglfResolveRenderbufferStorageMultisample; + GetBufferSubData = qopenglfResolveGetBufferSubData; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h new file mode 100644 index 0000000000..d3bd580fc7 --- /dev/null +++ b/src/gui/opengl/qopenglfunctions.h @@ -0,0 +1,2427 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLFUNCTIONS_H +#define QOPENGLFUNCTIONS_H + +#ifdef __GLEW_H__ +#warning qopenglfunctions.h is not compatible with GLEW, GLEW defines will be undefined +#warning To use GLEW with Qt, do not include or after glew.h +#endif + +#include +#include + +//#define Q_ENABLE_OPENGL_FUNCTIONS_DEBUG + +#ifdef Q_ENABLE_OPENGL_FUNCTIONS_DEBUG +#include +#define Q_OPENGL_FUNCTIONS_DEBUG \ + GLenum error = glGetError(); \ + if (error != GL_NO_ERROR) { \ + unsigned clamped = qMin(unsigned(error - GL_INVALID_ENUM), 4U); \ + const char *errors[] = { "GL_INVALID_ENUM", "GL_INVALID_VALUE", "GL_INVALID_OPERATION", "Unknown" }; \ + printf("GL error at %s:%d: %s\n", __FILE__, __LINE__, errors[clamped]); \ + int *value = 0; \ + *value = 0; \ + } +#else +#define Q_OPENGL_FUNCTIONS_DEBUG +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +// Types that aren't defined in all system's gl.h files. +typedef ptrdiff_t qopengl_GLintptr; +typedef ptrdiff_t qopengl_GLsizeiptr; + +#ifdef Q_WS_WIN +# define QOPENGLF_APIENTRY APIENTRY +#endif + +#ifndef Q_WS_MAC +# ifndef QOPENGLF_APIENTRYP +# ifdef QOPENGLF_APIENTRY +# define QOPENGLF_APIENTRYP QOPENGLF_APIENTRY * +# else +# define QOPENGLF_APIENTRY +# define QOPENGLF_APIENTRYP * +# endif +# endif +#else +# define QOPENGLF_APIENTRY +# define QOPENGLF_APIENTRYP * +#endif + +struct QOpenGLFunctionsPrivate; + +// Undefine any macros from GLEW, qopenglextensions_p.h, etc that +// may interfere with the definition of QOpenGLFunctions. +#undef glActiveTexture +#undef glAttachShader +#undef glBindAttribLocation +#undef glBindBuffer +#undef glBindFramebuffer +#undef glBindRenderbuffer +#undef glBlendColor +#undef glBlendEquation +#undef glBlendEquationSeparate +#undef glBlendFuncSeparate +#undef glBufferData +#undef glBufferSubData +#undef glCheckFramebufferStatus +#undef glClearDepthf +#undef glCompileShader +#undef glCompressedTexImage2D +#undef glCompressedTexSubImage2D +#undef glCreateProgram +#undef glCreateShader +#undef glDeleteBuffers +#undef glDeleteFramebuffers +#undef glDeleteProgram +#undef glDeleteRenderbuffers +#undef glDeleteShader +#undef glDepthRangef +#undef glDetachShader +#undef glDisableVertexAttribArray +#undef glEnableVertexAttribArray +#undef glFramebufferRenderbuffer +#undef glFramebufferTexture2D +#undef glGenBuffers +#undef glGenerateMipmap +#undef glGenFramebuffers +#undef glGenRenderbuffers +#undef glGetActiveAttrib +#undef glGetActiveUniform +#undef glGetAttachedShaders +#undef glGetAttribLocation +#undef glGetBufferParameteriv +#undef glGetFramebufferAttachmentParameteriv +#undef glGetProgramiv +#undef glGetProgramInfoLog +#undef glGetRenderbufferParameteriv +#undef glGetShaderiv +#undef glGetShaderInfoLog +#undef glGetShaderPrecisionFormat +#undef glGetShaderSource +#undef glGetUniformfv +#undef glGetUniformiv +#undef glGetUniformLocation +#undef glGetVertexAttribfv +#undef glGetVertexAttribiv +#undef glGetVertexAttribPointerv +#undef glIsBuffer +#undef glIsFramebuffer +#undef glIsProgram +#undef glIsRenderbuffer +#undef glIsShader +#undef glLinkProgram +#undef glReleaseShaderCompiler +#undef glRenderbufferStorage +#undef glSampleCoverage +#undef glShaderBinary +#undef glShaderSource +#undef glStencilFuncSeparate +#undef glStencilMaskSeparate +#undef glStencilOpSeparate +#undef glUniform1f +#undef glUniform1fv +#undef glUniform1i +#undef glUniform1iv +#undef glUniform2f +#undef glUniform2fv +#undef glUniform2i +#undef glUniform2iv +#undef glUniform3f +#undef glUniform3fv +#undef glUniform3i +#undef glUniform3iv +#undef glUniform4f +#undef glUniform4fv +#undef glUniform4i +#undef glUniform4iv +#undef glUniformMatrix2fv +#undef glUniformMatrix3fv +#undef glUniformMatrix4fv +#undef glUseProgram +#undef glValidateProgram +#undef glVertexAttrib1f +#undef glVertexAttrib1fv +#undef glVertexAttrib2f +#undef glVertexAttrib2fv +#undef glVertexAttrib3f +#undef glVertexAttrib3fv +#undef glVertexAttrib4f +#undef glVertexAttrib4fv +#undef glVertexAttribPointer + +class Q_GUI_EXPORT QOpenGLFunctions +{ +public: + QOpenGLFunctions(); + QOpenGLFunctions(QOpenGLContext *context); + ~QOpenGLFunctions() {} + + enum OpenGLFeature + { + Multitexture = 0x0001, + Shaders = 0x0002, + Buffers = 0x0004, + Framebuffers = 0x0008, + BlendColor = 0x0010, + BlendEquation = 0x0020, + BlendEquationSeparate = 0x0040, + BlendFuncSeparate = 0x0080, + BlendSubtract = 0x0100, + CompressedTextures = 0x0200, + Multisample = 0x0400, + StencilSeparate = 0x0800, + NPOTTextures = 0x1000 + }; + Q_DECLARE_FLAGS(OpenGLFeatures, OpenGLFeature) + + QOpenGLFunctions::OpenGLFeatures openGLFeatures() const; + bool hasOpenGLFeature(QOpenGLFunctions::OpenGLFeature feature) const; + + void initializeGLFunctions(); + + void glActiveTexture(GLenum texture); + void glAttachShader(GLuint program, GLuint shader); + void glBindAttribLocation(GLuint program, GLuint index, const char* name); + void glBindBuffer(GLenum target, GLuint buffer); + void glBindFramebuffer(GLenum target, GLuint framebuffer); + void glBindRenderbuffer(GLenum target, GLuint renderbuffer); + void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void glBlendEquation(GLenum mode); + void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha); + void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); + void glBufferData(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage); + void glBufferSubData(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data); + GLenum glCheckFramebufferStatus(GLenum target); + void glClearDepthf(GLclampf depth); + void glCompileShader(GLuint shader); + void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); + void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); + GLuint glCreateProgram(); + GLuint glCreateShader(GLenum type); + void glDeleteBuffers(GLsizei n, const GLuint* buffers); + void glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers); + void glDeleteProgram(GLuint program); + void glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers); + void glDeleteShader(GLuint shader); + void glDepthRangef(GLclampf zNear, GLclampf zFar); + void glDetachShader(GLuint program, GLuint shader); + void glDisableVertexAttribArray(GLuint index); + void glEnableVertexAttribArray(GLuint index); + void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); + void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void glGenBuffers(GLsizei n, GLuint* buffers); + void glGenerateMipmap(GLenum target); + void glGenFramebuffers(GLsizei n, GLuint* framebuffers); + void glGenRenderbuffers(GLsizei n, GLuint* renderbuffers); + void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); + void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); + void glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); + GLint glGetAttribLocation(GLuint program, const char* name); + void glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params); + void glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params); + void glGetProgramiv(GLuint program, GLenum pname, GLint* params); + void glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog); + void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params); + void glGetShaderiv(GLuint shader, GLenum pname, GLint* params); + void glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog); + void glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); + void glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source); + void glGetUniformfv(GLuint program, GLint location, GLfloat* params); + void glGetUniformiv(GLuint program, GLint location, GLint* params); + GLint glGetUniformLocation(GLuint program, const char* name); + void glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params); + void glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params); + void glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer); + GLboolean glIsBuffer(GLuint buffer); + GLboolean glIsFramebuffer(GLuint framebuffer); + GLboolean glIsProgram(GLuint program); + GLboolean glIsRenderbuffer(GLuint renderbuffer); + GLboolean glIsShader(GLuint shader); + void glLinkProgram(GLuint program); + void glReleaseShaderCompiler(); + void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + void glSampleCoverage(GLclampf value, GLboolean invert); + void glShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length); + void glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length); + void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); + void glStencilMaskSeparate(GLenum face, GLuint mask); + void glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + void glUniform1f(GLint location, GLfloat x); + void glUniform1fv(GLint location, GLsizei count, const GLfloat* v); + void glUniform1i(GLint location, GLint x); + void glUniform1iv(GLint location, GLsizei count, const GLint* v); + void glUniform2f(GLint location, GLfloat x, GLfloat y); + void glUniform2fv(GLint location, GLsizei count, const GLfloat* v); + void glUniform2i(GLint location, GLint x, GLint y); + void glUniform2iv(GLint location, GLsizei count, const GLint* v); + void glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z); + void glUniform3fv(GLint location, GLsizei count, const GLfloat* v); + void glUniform3i(GLint location, GLint x, GLint y, GLint z); + void glUniform3iv(GLint location, GLsizei count, const GLint* v); + void glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void glUniform4fv(GLint location, GLsizei count, const GLfloat* v); + void glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w); + void glUniform4iv(GLint location, GLsizei count, const GLint* v); + void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void glUseProgram(GLuint program); + void glValidateProgram(GLuint program); + void glVertexAttrib1f(GLuint indx, GLfloat x); + void glVertexAttrib1fv(GLuint indx, const GLfloat* values); + void glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y); + void glVertexAttrib2fv(GLuint indx, const GLfloat* values); + void glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z); + void glVertexAttrib3fv(GLuint indx, const GLfloat* values); + void glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void glVertexAttrib4fv(GLuint indx, const GLfloat* values); + void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); + +protected: + QOpenGLFunctionsPrivate *d_ptr; + static bool isInitialized(const QOpenGLFunctionsPrivate *d) { return d != 0; } +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLFunctions::OpenGLFeatures) + +struct QOpenGLFunctionsPrivate +{ + QOpenGLFunctionsPrivate(QOpenGLContext *ctx); + +#ifndef QT_OPENGL_ES_2 + void (QOPENGLF_APIENTRYP ActiveTexture)(GLenum texture); + void (QOPENGLF_APIENTRYP AttachShader)(GLuint program, GLuint shader); + void (QOPENGLF_APIENTRYP BindAttribLocation)(GLuint program, GLuint index, const char* name); + void (QOPENGLF_APIENTRYP BindBuffer)(GLenum target, GLuint buffer); + void (QOPENGLF_APIENTRYP BindFramebuffer)(GLenum target, GLuint framebuffer); + void (QOPENGLF_APIENTRYP BindRenderbuffer)(GLenum target, GLuint renderbuffer); + void (QOPENGLF_APIENTRYP BlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void (QOPENGLF_APIENTRYP BlendEquation)(GLenum mode); + void (QOPENGLF_APIENTRYP BlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha); + void (QOPENGLF_APIENTRYP BlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); + void (QOPENGLF_APIENTRYP BufferData)(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage); + void (QOPENGLF_APIENTRYP BufferSubData)(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data); + GLenum (QOPENGLF_APIENTRYP CheckFramebufferStatus)(GLenum target); + void (QOPENGLF_APIENTRYP CompileShader)(GLuint shader); + void (QOPENGLF_APIENTRYP CompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); + void (QOPENGLF_APIENTRYP CompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); + GLuint (QOPENGLF_APIENTRYP CreateProgram)(); + GLuint (QOPENGLF_APIENTRYP CreateShader)(GLenum type); + void (QOPENGLF_APIENTRYP DeleteBuffers)(GLsizei n, const GLuint* buffers); + void (QOPENGLF_APIENTRYP DeleteFramebuffers)(GLsizei n, const GLuint* framebuffers); + void (QOPENGLF_APIENTRYP DeleteProgram)(GLuint program); + void (QOPENGLF_APIENTRYP DeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers); + void (QOPENGLF_APIENTRYP DeleteShader)(GLuint shader); + void (QOPENGLF_APIENTRYP DetachShader)(GLuint program, GLuint shader); + void (QOPENGLF_APIENTRYP DisableVertexAttribArray)(GLuint index); + void (QOPENGLF_APIENTRYP EnableVertexAttribArray)(GLuint index); + void (QOPENGLF_APIENTRYP FramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); + void (QOPENGLF_APIENTRYP FramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); + void (QOPENGLF_APIENTRYP GenBuffers)(GLsizei n, GLuint* buffers); + void (QOPENGLF_APIENTRYP GenerateMipmap)(GLenum target); + void (QOPENGLF_APIENTRYP GenFramebuffers)(GLsizei n, GLuint* framebuffers); + void (QOPENGLF_APIENTRYP GenRenderbuffers)(GLsizei n, GLuint* renderbuffers); + void (QOPENGLF_APIENTRYP GetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); + void (QOPENGLF_APIENTRYP GetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); + void (QOPENGLF_APIENTRYP GetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); + GLint (QOPENGLF_APIENTRYP GetAttribLocation)(GLuint program, const char* name); + void (QOPENGLF_APIENTRYP GetBufferParameteriv)(GLenum target, GLenum pname, GLint* params); + void (QOPENGLF_APIENTRYP GetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params); + void (QOPENGLF_APIENTRYP GetProgramiv)(GLuint program, GLenum pname, GLint* params); + void (QOPENGLF_APIENTRYP GetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog); + void (QOPENGLF_APIENTRYP GetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params); + void (QOPENGLF_APIENTRYP GetShaderiv)(GLuint shader, GLenum pname, GLint* params); + void (QOPENGLF_APIENTRYP GetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog); + void (QOPENGLF_APIENTRYP GetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); + void (QOPENGLF_APIENTRYP GetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, char* source); + void (QOPENGLF_APIENTRYP GetUniformfv)(GLuint program, GLint location, GLfloat* params); + void (QOPENGLF_APIENTRYP GetUniformiv)(GLuint program, GLint location, GLint* params); + GLint (QOPENGLF_APIENTRYP GetUniformLocation)(GLuint program, const char* name); + void (QOPENGLF_APIENTRYP GetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params); + void (QOPENGLF_APIENTRYP GetVertexAttribiv)(GLuint index, GLenum pname, GLint* params); + void (QOPENGLF_APIENTRYP GetVertexAttribPointerv)(GLuint index, GLenum pname, void** pointer); + GLboolean (QOPENGLF_APIENTRYP IsBuffer)(GLuint buffer); + GLboolean (QOPENGLF_APIENTRYP IsFramebuffer)(GLuint framebuffer); + GLboolean (QOPENGLF_APIENTRYP IsProgram)(GLuint program); + GLboolean (QOPENGLF_APIENTRYP IsRenderbuffer)(GLuint renderbuffer); + GLboolean (QOPENGLF_APIENTRYP IsShader)(GLuint shader); + void (QOPENGLF_APIENTRYP LinkProgram)(GLuint program); + void (QOPENGLF_APIENTRYP ReleaseShaderCompiler)(); + void (QOPENGLF_APIENTRYP RenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); + void (QOPENGLF_APIENTRYP SampleCoverage)(GLclampf value, GLboolean invert); + void (QOPENGLF_APIENTRYP ShaderBinary)(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length); + void (QOPENGLF_APIENTRYP ShaderSource)(GLuint shader, GLsizei count, const char** string, const GLint* length); + void (QOPENGLF_APIENTRYP StencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask); + void (QOPENGLF_APIENTRYP StencilMaskSeparate)(GLenum face, GLuint mask); + void (QOPENGLF_APIENTRYP StencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + void (QOPENGLF_APIENTRYP Uniform1f)(GLint location, GLfloat x); + void (QOPENGLF_APIENTRYP Uniform1fv)(GLint location, GLsizei count, const GLfloat* v); + void (QOPENGLF_APIENTRYP Uniform1i)(GLint location, GLint x); + void (QOPENGLF_APIENTRYP Uniform1iv)(GLint location, GLsizei count, const GLint* v); + void (QOPENGLF_APIENTRYP Uniform2f)(GLint location, GLfloat x, GLfloat y); + void (QOPENGLF_APIENTRYP Uniform2fv)(GLint location, GLsizei count, const GLfloat* v); + void (QOPENGLF_APIENTRYP Uniform2i)(GLint location, GLint x, GLint y); + void (QOPENGLF_APIENTRYP Uniform2iv)(GLint location, GLsizei count, const GLint* v); + void (QOPENGLF_APIENTRYP Uniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z); + void (QOPENGLF_APIENTRYP Uniform3fv)(GLint location, GLsizei count, const GLfloat* v); + void (QOPENGLF_APIENTRYP Uniform3i)(GLint location, GLint x, GLint y, GLint z); + void (QOPENGLF_APIENTRYP Uniform3iv)(GLint location, GLsizei count, const GLint* v); + void (QOPENGLF_APIENTRYP Uniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (QOPENGLF_APIENTRYP Uniform4fv)(GLint location, GLsizei count, const GLfloat* v); + void (QOPENGLF_APIENTRYP Uniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w); + void (QOPENGLF_APIENTRYP Uniform4iv)(GLint location, GLsizei count, const GLint* v); + void (QOPENGLF_APIENTRYP UniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (QOPENGLF_APIENTRYP UniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (QOPENGLF_APIENTRYP UniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); + void (QOPENGLF_APIENTRYP UseProgram)(GLuint program); + void (QOPENGLF_APIENTRYP ValidateProgram)(GLuint program); + void (QOPENGLF_APIENTRYP VertexAttrib1f)(GLuint indx, GLfloat x); + void (QOPENGLF_APIENTRYP VertexAttrib1fv)(GLuint indx, const GLfloat* values); + void (QOPENGLF_APIENTRYP VertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y); + void (QOPENGLF_APIENTRYP VertexAttrib2fv)(GLuint indx, const GLfloat* values); + void (QOPENGLF_APIENTRYP VertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z); + void (QOPENGLF_APIENTRYP VertexAttrib3fv)(GLuint indx, const GLfloat* values); + void (QOPENGLF_APIENTRYP VertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void (QOPENGLF_APIENTRYP VertexAttrib4fv)(GLuint indx, const GLfloat* values); + void (QOPENGLF_APIENTRYP VertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); +#endif +}; + +inline void QOpenGLFunctions::glActiveTexture(GLenum texture) +{ +#if defined(QT_OPENGL_ES_2) + ::glActiveTexture(texture); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->ActiveTexture(texture); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glAttachShader(GLuint program, GLuint shader) +{ +#if defined(QT_OPENGL_ES_2) + ::glAttachShader(program, shader); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->AttachShader(program, shader); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glBindAttribLocation(GLuint program, GLuint index, const char* name) +{ +#if defined(QT_OPENGL_ES_2) + ::glBindAttribLocation(program, index, name); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->BindAttribLocation(program, index, name); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glBindBuffer(GLenum target, GLuint buffer) +{ +#if defined(QT_OPENGL_ES_2) + ::glBindBuffer(target, buffer); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->BindBuffer(target, buffer); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glBindFramebuffer(GLenum target, GLuint framebuffer) +{ +#if defined(QT_OPENGL_ES_2) + ::glBindFramebuffer(target, framebuffer); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->BindFramebuffer(target, framebuffer); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glBindRenderbuffer(GLenum target, GLuint renderbuffer) +{ +#if defined(QT_OPENGL_ES_2) + ::glBindRenderbuffer(target, renderbuffer); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->BindRenderbuffer(target, renderbuffer); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ +#if defined(QT_OPENGL_ES_2) + ::glBlendColor(red, green, blue, alpha); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->BlendColor(red, green, blue, alpha); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glBlendEquation(GLenum mode) +{ +#if defined(QT_OPENGL_ES_2) + ::glBlendEquation(mode); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->BlendEquation(mode); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ +#if defined(QT_OPENGL_ES_2) + ::glBlendEquationSeparate(modeRGB, modeAlpha); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->BlendEquationSeparate(modeRGB, modeAlpha); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ +#if defined(QT_OPENGL_ES_2) + ::glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glBufferData(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage) +{ +#if defined(QT_OPENGL_ES_2) + ::glBufferData(target, size, data, usage); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->BufferData(target, size, data, usage); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glBufferSubData(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data) +{ +#if defined(QT_OPENGL_ES_2) + ::glBufferSubData(target, offset, size, data); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->BufferSubData(target, offset, size, data); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline GLenum QOpenGLFunctions::glCheckFramebufferStatus(GLenum target) +{ +#if defined(QT_OPENGL_ES_2) + GLenum result = ::glCheckFramebufferStatus(target); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + GLenum result = d_ptr->CheckFramebufferStatus(target); +#endif + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline void QOpenGLFunctions::glClearDepthf(GLclampf depth) +{ +#ifndef QT_OPENGL_ES + ::glClearDepth(depth); +#else + ::glClearDepthf(depth); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glCompileShader(GLuint shader) +{ +#if defined(QT_OPENGL_ES_2) + ::glCompileShader(shader); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->CompileShader(shader); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data) +{ +#if defined(QT_OPENGL_ES_2) + ::glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->CompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) +{ +#if defined(QT_OPENGL_ES_2) + ::glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline GLuint QOpenGLFunctions::glCreateProgram() +{ +#if defined(QT_OPENGL_ES_2) + GLuint result = ::glCreateProgram(); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + GLuint result = d_ptr->CreateProgram(); +#endif + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline GLuint QOpenGLFunctions::glCreateShader(GLenum type) +{ +#if defined(QT_OPENGL_ES_2) + GLuint result = ::glCreateShader(type); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + GLuint result = d_ptr->CreateShader(type); +#endif + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline void QOpenGLFunctions::glDeleteBuffers(GLsizei n, const GLuint* buffers) +{ +#if defined(QT_OPENGL_ES_2) + ::glDeleteBuffers(n, buffers); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->DeleteBuffers(n, buffers); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) +{ +#if defined(QT_OPENGL_ES_2) + ::glDeleteFramebuffers(n, framebuffers); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->DeleteFramebuffers(n, framebuffers); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glDeleteProgram(GLuint program) +{ +#if defined(QT_OPENGL_ES_2) + ::glDeleteProgram(program); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->DeleteProgram(program); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) +{ +#if defined(QT_OPENGL_ES_2) + ::glDeleteRenderbuffers(n, renderbuffers); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->DeleteRenderbuffers(n, renderbuffers); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glDeleteShader(GLuint shader) +{ +#if defined(QT_OPENGL_ES_2) + ::glDeleteShader(shader); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->DeleteShader(shader); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glDepthRangef(GLclampf zNear, GLclampf zFar) +{ +#ifndef QT_OPENGL_ES + ::glDepthRange(zNear, zFar); +#else + ::glDepthRangef(zNear, zFar); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glDetachShader(GLuint program, GLuint shader) +{ +#if defined(QT_OPENGL_ES_2) + ::glDetachShader(program, shader); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->DetachShader(program, shader); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glDisableVertexAttribArray(GLuint index) +{ +#if defined(QT_OPENGL_ES_2) + ::glDisableVertexAttribArray(index); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->DisableVertexAttribArray(index); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glEnableVertexAttribArray(GLuint index) +{ +#if defined(QT_OPENGL_ES_2) + ::glEnableVertexAttribArray(index); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->EnableVertexAttribArray(index); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +{ +#if defined(QT_OPENGL_ES_2) + ::glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +{ +#if defined(QT_OPENGL_ES_2) + ::glFramebufferTexture2D(target, attachment, textarget, texture, level); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->FramebufferTexture2D(target, attachment, textarget, texture, level); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGenBuffers(GLsizei n, GLuint* buffers) +{ +#if defined(QT_OPENGL_ES_2) + ::glGenBuffers(n, buffers); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GenBuffers(n, buffers); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGenerateMipmap(GLenum target) +{ +#if defined(QT_OPENGL_ES_2) + ::glGenerateMipmap(target); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GenerateMipmap(target); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGenFramebuffers(GLsizei n, GLuint* framebuffers) +{ +#if defined(QT_OPENGL_ES_2) + ::glGenFramebuffers(n, framebuffers); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GenFramebuffers(n, framebuffers); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) +{ +#if defined(QT_OPENGL_ES_2) + ::glGenRenderbuffers(n, renderbuffers); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GenRenderbuffers(n, renderbuffers); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetActiveAttrib(program, index, bufsize, length, size, type, name); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetActiveAttrib(program, index, bufsize, length, size, type, name); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetActiveUniform(program, index, bufsize, length, size, type, name); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetActiveUniform(program, index, bufsize, length, size, type, name); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetAttachedShaders(program, maxcount, count, shaders); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetAttachedShaders(program, maxcount, count, shaders); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline GLint QOpenGLFunctions::glGetAttribLocation(GLuint program, const char* name) +{ +#if defined(QT_OPENGL_ES_2) + GLint result = ::glGetAttribLocation(program, name); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + GLint result = d_ptr->GetAttribLocation(program, name); +#endif + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline void QOpenGLFunctions::glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetBufferParameteriv(target, pname, params); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetBufferParameteriv(target, pname, params); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetFramebufferAttachmentParameteriv(target, attachment, pname, params); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetFramebufferAttachmentParameteriv(target, attachment, pname, params); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetProgramiv(GLuint program, GLenum pname, GLint* params) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetProgramiv(program, pname, params); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetProgramiv(program, pname, params); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetProgramInfoLog(program, bufsize, length, infolog); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetProgramInfoLog(program, bufsize, length, infolog); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetRenderbufferParameteriv(target, pname, params); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetRenderbufferParameteriv(target, pname, params); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetShaderiv(GLuint shader, GLenum pname, GLint* params) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetShaderiv(shader, pname, params); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetShaderiv(shader, pname, params); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetShaderInfoLog(shader, bufsize, length, infolog); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetShaderInfoLog(shader, bufsize, length, infolog); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetShaderPrecisionFormat(shadertype, precisiontype, range, precision); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetShaderSource(shader, bufsize, length, source); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetShaderSource(shader, bufsize, length, source); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetUniformfv(GLuint program, GLint location, GLfloat* params) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetUniformfv(program, location, params); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetUniformfv(program, location, params); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetUniformiv(GLuint program, GLint location, GLint* params) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetUniformiv(program, location, params); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetUniformiv(program, location, params); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline GLint QOpenGLFunctions::glGetUniformLocation(GLuint program, const char* name) +{ +#if defined(QT_OPENGL_ES_2) + GLint result = ::glGetUniformLocation(program, name); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + GLint result = d_ptr->GetUniformLocation(program, name); +#endif + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline void QOpenGLFunctions::glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetVertexAttribfv(index, pname, params); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetVertexAttribfv(index, pname, params); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetVertexAttribiv(index, pname, params); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetVertexAttribiv(index, pname, params); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer) +{ +#if defined(QT_OPENGL_ES_2) + ::glGetVertexAttribPointerv(index, pname, pointer); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->GetVertexAttribPointerv(index, pname, pointer); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline GLboolean QOpenGLFunctions::glIsBuffer(GLuint buffer) +{ +#if defined(QT_OPENGL_ES_2) + GLboolean result = ::glIsBuffer(buffer); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + GLboolean result = d_ptr->IsBuffer(buffer); +#endif + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline GLboolean QOpenGLFunctions::glIsFramebuffer(GLuint framebuffer) +{ +#if defined(QT_OPENGL_ES_2) + GLboolean result = ::glIsFramebuffer(framebuffer); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + GLboolean result = d_ptr->IsFramebuffer(framebuffer); +#endif + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline GLboolean QOpenGLFunctions::glIsProgram(GLuint program) +{ +#if defined(QT_OPENGL_ES_2) + GLboolean result = ::glIsProgram(program); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + GLboolean result = d_ptr->IsProgram(program); +#endif + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline GLboolean QOpenGLFunctions::glIsRenderbuffer(GLuint renderbuffer) +{ +#if defined(QT_OPENGL_ES_2) + GLboolean result = ::glIsRenderbuffer(renderbuffer); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + GLboolean result = d_ptr->IsRenderbuffer(renderbuffer); +#endif + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline GLboolean QOpenGLFunctions::glIsShader(GLuint shader) +{ +#if defined(QT_OPENGL_ES_2) + GLboolean result = ::glIsShader(shader); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + GLboolean result = d_ptr->IsShader(shader); +#endif + Q_OPENGL_FUNCTIONS_DEBUG + return result; +} + +inline void QOpenGLFunctions::glLinkProgram(GLuint program) +{ +#if defined(QT_OPENGL_ES_2) + ::glLinkProgram(program); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->LinkProgram(program); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glReleaseShaderCompiler() +{ +#if defined(QT_OPENGL_ES_2) + ::glReleaseShaderCompiler(); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->ReleaseShaderCompiler(); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ +#if defined(QT_OPENGL_ES_2) + ::glRenderbufferStorage(target, internalformat, width, height); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->RenderbufferStorage(target, internalformat, width, height); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glSampleCoverage(GLclampf value, GLboolean invert) +{ +#if defined(QT_OPENGL_ES_2) + ::glSampleCoverage(value, invert); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->SampleCoverage(value, invert); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length) +{ +#if defined(QT_OPENGL_ES_2) + ::glShaderBinary(n, shaders, binaryformat, binary, length); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->ShaderBinary(n, shaders, binaryformat, binary, length); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length) +{ +#if defined(QT_OPENGL_ES_2) + ::glShaderSource(shader, count, string, length); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->ShaderSource(shader, count, string, length); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ +#if defined(QT_OPENGL_ES_2) + ::glStencilFuncSeparate(face, func, ref, mask); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->StencilFuncSeparate(face, func, ref, mask); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glStencilMaskSeparate(GLenum face, GLuint mask) +{ +#if defined(QT_OPENGL_ES_2) + ::glStencilMaskSeparate(face, mask); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->StencilMaskSeparate(face, mask); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ +#if defined(QT_OPENGL_ES_2) + ::glStencilOpSeparate(face, fail, zfail, zpass); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->StencilOpSeparate(face, fail, zfail, zpass); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform1f(GLint location, GLfloat x) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform1f(location, x); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform1f(location, x); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform1fv(location, count, v); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform1fv(location, count, v); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform1i(GLint location, GLint x) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform1i(location, x); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform1i(location, x); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform1iv(GLint location, GLsizei count, const GLint* v) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform1iv(location, count, v); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform1iv(location, count, v); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform2f(GLint location, GLfloat x, GLfloat y) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform2f(location, x, y); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform2f(location, x, y); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform2fv(GLint location, GLsizei count, const GLfloat* v) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform2fv(location, count, v); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform2fv(location, count, v); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform2i(GLint location, GLint x, GLint y) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform2i(location, x, y); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform2i(location, x, y); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform2iv(GLint location, GLsizei count, const GLint* v) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform2iv(location, count, v); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform2iv(location, count, v); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform3f(location, x, y, z); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform3f(location, x, y, z); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform3fv(GLint location, GLsizei count, const GLfloat* v) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform3fv(location, count, v); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform3fv(location, count, v); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform3i(GLint location, GLint x, GLint y, GLint z) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform3i(location, x, y, z); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform3i(location, x, y, z); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform3iv(GLint location, GLsizei count, const GLint* v) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform3iv(location, count, v); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform3iv(location, count, v); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform4f(location, x, y, z, w); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform4f(location, x, y, z, w); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform4fv(GLint location, GLsizei count, const GLfloat* v) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform4fv(location, count, v); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform4fv(location, count, v); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform4i(location, x, y, z, w); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform4i(location, x, y, z, w); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniform4iv(GLint location, GLsizei count, const GLint* v) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniform4iv(location, count, v); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->Uniform4iv(location, count, v); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniformMatrix2fv(location, count, transpose, value); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->UniformMatrix2fv(location, count, transpose, value); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniformMatrix3fv(location, count, transpose, value); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->UniformMatrix3fv(location, count, transpose, value); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ +#if defined(QT_OPENGL_ES_2) + ::glUniformMatrix4fv(location, count, transpose, value); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->UniformMatrix4fv(location, count, transpose, value); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glUseProgram(GLuint program) +{ +#if defined(QT_OPENGL_ES_2) + ::glUseProgram(program); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->UseProgram(program); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glValidateProgram(GLuint program) +{ +#if defined(QT_OPENGL_ES_2) + ::glValidateProgram(program); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->ValidateProgram(program); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glVertexAttrib1f(GLuint indx, GLfloat x) +{ +#if defined(QT_OPENGL_ES_2) + ::glVertexAttrib1f(indx, x); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->VertexAttrib1f(indx, x); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glVertexAttrib1fv(GLuint indx, const GLfloat* values) +{ +#if defined(QT_OPENGL_ES_2) + ::glVertexAttrib1fv(indx, values); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->VertexAttrib1fv(indx, values); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) +{ +#if defined(QT_OPENGL_ES_2) + ::glVertexAttrib2f(indx, x, y); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->VertexAttrib2f(indx, x, y); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glVertexAttrib2fv(GLuint indx, const GLfloat* values) +{ +#if defined(QT_OPENGL_ES_2) + ::glVertexAttrib2fv(indx, values); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->VertexAttrib2fv(indx, values); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) +{ +#if defined(QT_OPENGL_ES_2) + ::glVertexAttrib3f(indx, x, y, z); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->VertexAttrib3f(indx, x, y, z); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glVertexAttrib3fv(GLuint indx, const GLfloat* values) +{ +#if defined(QT_OPENGL_ES_2) + ::glVertexAttrib3fv(indx, values); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->VertexAttrib3fv(indx, values); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ +#if defined(QT_OPENGL_ES_2) + ::glVertexAttrib4f(indx, x, y, z, w); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->VertexAttrib4f(indx, x, y, z, w); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glVertexAttrib4fv(GLuint indx, const GLfloat* values) +{ +#if defined(QT_OPENGL_ES_2) + ::glVertexAttrib4fv(indx, values); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->VertexAttrib4fv(indx, values); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +inline void QOpenGLFunctions::glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr) +{ +#if defined(QT_OPENGL_ES_2) + ::glVertexAttribPointer(indx, size, type, normalized, stride, ptr); +#else + Q_ASSERT(QOpenGLFunctions::isInitialized(d_ptr)); + d_ptr->VertexAttribPointer(indx, size, type, normalized, stride, ptr); +#endif + Q_OPENGL_FUNCTIONS_DEBUG +} + +#ifndef GL_ACTIVE_ATTRIBUTE_MAX_LENGTH +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#endif +#ifndef GL_ACTIVE_ATTRIBUTES +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#endif +#ifndef GL_ACTIVE_TEXTURE +#define GL_ACTIVE_TEXTURE 0x84E0 +#endif +#ifndef GL_ACTIVE_UNIFORM_MAX_LENGTH +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#endif +#ifndef GL_ACTIVE_UNIFORMS +#define GL_ACTIVE_UNIFORMS 0x8B86 +#endif +#ifndef GL_ALIASED_LINE_WIDTH_RANGE +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#endif +#ifndef GL_ALIASED_POINT_SIZE_RANGE +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#endif +#ifndef GL_ALPHA +#define GL_ALPHA 0x1906 +#endif +#ifndef GL_ALPHA_BITS +#define GL_ALPHA_BITS 0x0D55 +#endif +#ifndef GL_ALWAYS +#define GL_ALWAYS 0x0207 +#endif +#ifndef GL_ARRAY_BUFFER +#define GL_ARRAY_BUFFER 0x8892 +#endif +#ifndef GL_ARRAY_BUFFER_BINDING +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#endif +#ifndef GL_ATTACHED_SHADERS +#define GL_ATTACHED_SHADERS 0x8B85 +#endif +#ifndef GL_BACK +#define GL_BACK 0x0405 +#endif +#ifndef GL_BLEND +#define GL_BLEND 0x0BE2 +#endif +#ifndef GL_BLEND_COLOR +#define GL_BLEND_COLOR 0x8005 +#endif +#ifndef GL_BLEND_DST_ALPHA +#define GL_BLEND_DST_ALPHA 0x80CA +#endif +#ifndef GL_BLEND_DST_RGB +#define GL_BLEND_DST_RGB 0x80C8 +#endif +#ifndef GL_BLEND_EQUATION +#define GL_BLEND_EQUATION 0x8009 +#endif +#ifndef GL_BLEND_EQUATION_ALPHA +#define GL_BLEND_EQUATION_ALPHA 0x883D +#endif +#ifndef GL_BLEND_EQUATION_RGB +#define GL_BLEND_EQUATION_RGB 0x8009 +#endif +#ifndef GL_BLEND_SRC_ALPHA +#define GL_BLEND_SRC_ALPHA 0x80CB +#endif +#ifndef GL_BLEND_SRC_RGB +#define GL_BLEND_SRC_RGB 0x80C9 +#endif +#ifndef GL_BLUE_BITS +#define GL_BLUE_BITS 0x0D54 +#endif +#ifndef GL_BOOL +#define GL_BOOL 0x8B56 +#endif +#ifndef GL_BOOL_VEC2 +#define GL_BOOL_VEC2 0x8B57 +#endif +#ifndef GL_BOOL_VEC3 +#define GL_BOOL_VEC3 0x8B58 +#endif +#ifndef GL_BOOL_VEC4 +#define GL_BOOL_VEC4 0x8B59 +#endif +#ifndef GL_BUFFER_SIZE +#define GL_BUFFER_SIZE 0x8764 +#endif +#ifndef GL_BUFFER_USAGE +#define GL_BUFFER_USAGE 0x8765 +#endif +#ifndef GL_BYTE +#define GL_BYTE 0x1400 +#endif +#ifndef GL_CCW +#define GL_CCW 0x0901 +#endif +#ifndef GL_CLAMP_TO_EDGE +#define GL_CLAMP_TO_EDGE 0x812F +#endif +#ifndef GL_COLOR_ATTACHMENT0 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#endif +#ifndef GL_COLOR_BUFFER_BIT +#define GL_COLOR_BUFFER_BIT 0x00004000 +#endif +#ifndef GL_COLOR_CLEAR_VALUE +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#endif +#ifndef GL_COLOR_WRITEMASK +#define GL_COLOR_WRITEMASK 0x0C23 +#endif +#ifndef GL_COMPILE_STATUS +#define GL_COMPILE_STATUS 0x8B81 +#endif +#ifndef GL_COMPRESSED_TEXTURE_FORMATS +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#endif +#ifndef GL_CONSTANT_ALPHA +#define GL_CONSTANT_ALPHA 0x8003 +#endif +#ifndef GL_CONSTANT_COLOR +#define GL_CONSTANT_COLOR 0x8001 +#endif +#ifndef GL_CULL_FACE +#define GL_CULL_FACE 0x0B44 +#endif +#ifndef GL_CULL_FACE_MODE +#define GL_CULL_FACE_MODE 0x0B45 +#endif +#ifndef GL_CURRENT_PROGRAM +#define GL_CURRENT_PROGRAM 0x8B8D +#endif +#ifndef GL_CURRENT_VERTEX_ATTRIB +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#endif +#ifndef GL_CW +#define GL_CW 0x0900 +#endif +#ifndef GL_DECR +#define GL_DECR 0x1E03 +#endif +#ifndef GL_DECR_WRAP +#define GL_DECR_WRAP 0x8508 +#endif +#ifndef GL_DELETE_STATUS +#define GL_DELETE_STATUS 0x8B80 +#endif +#ifndef GL_DEPTH_ATTACHMENT +#define GL_DEPTH_ATTACHMENT 0x8D00 +#endif +#ifndef GL_DEPTH_BITS +#define GL_DEPTH_BITS 0x0D56 +#endif +#ifndef GL_DEPTH_BUFFER_BIT +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#endif +#ifndef GL_DEPTH_CLEAR_VALUE +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#endif +#ifndef GL_DEPTH_COMPONENT +#define GL_DEPTH_COMPONENT 0x1902 +#endif +#ifndef GL_DEPTH_COMPONENT16 +#define GL_DEPTH_COMPONENT16 0x81A5 +#endif +#ifndef GL_DEPTH_FUNC +#define GL_DEPTH_FUNC 0x0B74 +#endif +#ifndef GL_DEPTH_RANGE +#define GL_DEPTH_RANGE 0x0B70 +#endif +#ifndef GL_DEPTH_TEST +#define GL_DEPTH_TEST 0x0B71 +#endif +#ifndef GL_DEPTH_WRITEMASK +#define GL_DEPTH_WRITEMASK 0x0B72 +#endif +#ifndef GL_DITHER +#define GL_DITHER 0x0BD0 +#endif +#ifndef GL_DONT_CARE +#define GL_DONT_CARE 0x1100 +#endif +#ifndef GL_DST_ALPHA +#define GL_DST_ALPHA 0x0304 +#endif +#ifndef GL_DST_COLOR +#define GL_DST_COLOR 0x0306 +#endif +#ifndef GL_DYNAMIC_DRAW +#define GL_DYNAMIC_DRAW 0x88E8 +#endif +#ifndef GL_ELEMENT_ARRAY_BUFFER +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#endif +#ifndef GL_ELEMENT_ARRAY_BUFFER_BINDING +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#endif +#ifndef GL_EQUAL +#define GL_EQUAL 0x0202 +#endif +#ifndef GL_EXTENSIONS +#define GL_EXTENSIONS 0x1F03 +#endif +#ifndef GL_FALSE +#define GL_FALSE 0 +#endif +#ifndef GL_FASTEST +#define GL_FASTEST 0x1101 +#endif +#ifndef GL_FIXED +#define GL_FIXED 0x140C +#endif +#ifndef GL_FLOAT +#define GL_FLOAT 0x1406 +#endif +#ifndef GL_FLOAT_MAT2 +#define GL_FLOAT_MAT2 0x8B5A +#endif +#ifndef GL_FLOAT_MAT3 +#define GL_FLOAT_MAT3 0x8B5B +#endif +#ifndef GL_FLOAT_MAT4 +#define GL_FLOAT_MAT4 0x8B5C +#endif +#ifndef GL_FLOAT_VEC2 +#define GL_FLOAT_VEC2 0x8B50 +#endif +#ifndef GL_FLOAT_VEC3 +#define GL_FLOAT_VEC3 0x8B51 +#endif +#ifndef GL_FLOAT_VEC4 +#define GL_FLOAT_VEC4 0x8B52 +#endif +#ifndef GL_FRAGMENT_SHADER +#define GL_FRAGMENT_SHADER 0x8B30 +#endif +#ifndef GL_FRAMEBUFFER +#define GL_FRAMEBUFFER 0x8D40 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#endif +#ifndef GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#endif +#ifndef GL_FRAMEBUFFER_BINDING +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#endif +#ifndef GL_FRAMEBUFFER_COMPLETE +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#endif +#ifndef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#endif +#ifndef GL_FRAMEBUFFER_UNSUPPORTED +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#endif +#ifndef GL_FRONT +#define GL_FRONT 0x0404 +#endif +#ifndef GL_FRONT_AND_BACK +#define GL_FRONT_AND_BACK 0x0408 +#endif +#ifndef GL_FRONT_FACE +#define GL_FRONT_FACE 0x0B46 +#endif +#ifndef GL_FUNC_ADD +#define GL_FUNC_ADD 0x8006 +#endif +#ifndef GL_FUNC_REVERSE_SUBTRACT +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#endif +#ifndef GL_FUNC_SUBTRACT +#define GL_FUNC_SUBTRACT 0x800A +#endif +#ifndef GL_GENERATE_MIPMAP_HINT +#define GL_GENERATE_MIPMAP_HINT 0x8192 +#endif +#ifndef GL_GEQUAL +#define GL_GEQUAL 0x0206 +#endif +#ifndef GL_GREATER +#define GL_GREATER 0x0204 +#endif +#ifndef GL_GREEN_BITS +#define GL_GREEN_BITS 0x0D53 +#endif +#ifndef GL_HIGH_FLOAT +#define GL_HIGH_FLOAT 0x8DF2 +#endif +#ifndef GL_HIGH_INT +#define GL_HIGH_INT 0x8DF5 +#endif +#ifndef GL_IMPLEMENTATION_COLOR_READ_FORMAT +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#endif +#ifndef GL_IMPLEMENTATION_COLOR_READ_TYPE +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#endif +#ifndef GL_INCR +#define GL_INCR 0x1E02 +#endif +#ifndef GL_INCR_WRAP +#define GL_INCR_WRAP 0x8507 +#endif +#ifndef GL_INFO_LOG_LENGTH +#define GL_INFO_LOG_LENGTH 0x8B84 +#endif +#ifndef GL_INT +#define GL_INT 0x1404 +#endif +#ifndef GL_INT_VEC2 +#define GL_INT_VEC2 0x8B53 +#endif +#ifndef GL_INT_VEC3 +#define GL_INT_VEC3 0x8B54 +#endif +#ifndef GL_INT_VEC4 +#define GL_INT_VEC4 0x8B55 +#endif +#ifndef GL_INVALID_ENUM +#define GL_INVALID_ENUM 0x0500 +#endif +#ifndef GL_INVALID_FRAMEBUFFER_OPERATION +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#endif +#ifndef GL_INVALID_OPERATION +#define GL_INVALID_OPERATION 0x0502 +#endif +#ifndef GL_INVALID_VALUE +#define GL_INVALID_VALUE 0x0501 +#endif +#ifndef GL_INVERT +#define GL_INVERT 0x150A +#endif +#ifndef GL_KEEP +#define GL_KEEP 0x1E00 +#endif +#ifndef GL_LEQUAL +#define GL_LEQUAL 0x0203 +#endif +#ifndef GL_LESS +#define GL_LESS 0x0201 +#endif +#ifndef GL_LINEAR +#define GL_LINEAR 0x2601 +#endif +#ifndef GL_LINEAR_MIPMAP_LINEAR +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#endif +#ifndef GL_LINEAR_MIPMAP_NEAREST +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#endif +#ifndef GL_LINE_LOOP +#define GL_LINE_LOOP 0x0002 +#endif +#ifndef GL_LINES +#define GL_LINES 0x0001 +#endif +#ifndef GL_LINE_STRIP +#define GL_LINE_STRIP 0x0003 +#endif +#ifndef GL_LINE_WIDTH +#define GL_LINE_WIDTH 0x0B21 +#endif +#ifndef GL_LINK_STATUS +#define GL_LINK_STATUS 0x8B82 +#endif +#ifndef GL_LOW_FLOAT +#define GL_LOW_FLOAT 0x8DF0 +#endif +#ifndef GL_LOW_INT +#define GL_LOW_INT 0x8DF3 +#endif +#ifndef GL_LUMINANCE +#define GL_LUMINANCE 0x1909 +#endif +#ifndef GL_LUMINANCE_ALPHA +#define GL_LUMINANCE_ALPHA 0x190A +#endif +#ifndef GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#endif +#ifndef GL_MAX_CUBE_MAP_TEXTURE_SIZE +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#endif +#ifndef GL_MAX_FRAGMENT_UNIFORM_VECTORS +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#endif +#ifndef GL_MAX_RENDERBUFFER_SIZE +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#endif +#ifndef GL_MAX_TEXTURE_IMAGE_UNITS +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#endif +#ifndef GL_MAX_TEXTURE_SIZE +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#endif +#ifndef GL_MAX_VARYING_VECTORS +#define GL_MAX_VARYING_VECTORS 0x8DFC +#endif +#ifndef GL_MAX_VERTEX_ATTRIBS +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#endif +#ifndef GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#endif +#ifndef GL_MAX_VERTEX_UNIFORM_VECTORS +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#endif +#ifndef GL_MAX_VIEWPORT_DIMS +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#endif +#ifndef GL_MEDIUM_FLOAT +#define GL_MEDIUM_FLOAT 0x8DF1 +#endif +#ifndef GL_MEDIUM_INT +#define GL_MEDIUM_INT 0x8DF4 +#endif +#ifndef GL_MIRRORED_REPEAT +#define GL_MIRRORED_REPEAT 0x8370 +#endif +#ifndef GL_NEAREST +#define GL_NEAREST 0x2600 +#endif +#ifndef GL_NEAREST_MIPMAP_LINEAR +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#endif +#ifndef GL_NEAREST_MIPMAP_NEAREST +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#endif +#ifndef GL_NEVER +#define GL_NEVER 0x0200 +#endif +#ifndef GL_NICEST +#define GL_NICEST 0x1102 +#endif +#ifndef GL_NO_ERROR +#define GL_NO_ERROR 0 +#endif +#ifndef GL_NONE +#define GL_NONE 0 +#endif +#ifndef GL_NOTEQUAL +#define GL_NOTEQUAL 0x0205 +#endif +#ifndef GL_NUM_COMPRESSED_TEXTURE_FORMATS +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#endif +#ifndef GL_NUM_SHADER_BINARY_FORMATS +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#endif +#ifndef GL_ONE +#define GL_ONE 1 +#endif +#ifndef GL_ONE_MINUS_CONSTANT_ALPHA +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#endif +#ifndef GL_ONE_MINUS_CONSTANT_COLOR +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#endif +#ifndef GL_ONE_MINUS_DST_ALPHA +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#endif +#ifndef GL_ONE_MINUS_DST_COLOR +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#endif +#ifndef GL_ONE_MINUS_SRC_ALPHA +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#endif +#ifndef GL_ONE_MINUS_SRC_COLOR +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#endif +#ifndef GL_OUT_OF_MEMORY +#define GL_OUT_OF_MEMORY 0x0505 +#endif +#ifndef GL_PACK_ALIGNMENT +#define GL_PACK_ALIGNMENT 0x0D05 +#endif +#ifndef GL_POINTS +#define GL_POINTS 0x0000 +#endif +#ifndef GL_POLYGON_OFFSET_FACTOR +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#endif +#ifndef GL_POLYGON_OFFSET_FILL +#define GL_POLYGON_OFFSET_FILL 0x8037 +#endif +#ifndef GL_POLYGON_OFFSET_UNITS +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#endif +#ifndef GL_RED_BITS +#define GL_RED_BITS 0x0D52 +#endif +#ifndef GL_RENDERBUFFER +#define GL_RENDERBUFFER 0x8D41 +#endif +#ifndef GL_RENDERBUFFER_ALPHA_SIZE +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#endif +#ifndef GL_RENDERBUFFER_BINDING +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#endif +#ifndef GL_RENDERBUFFER_BLUE_SIZE +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#endif +#ifndef GL_RENDERBUFFER_DEPTH_SIZE +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#endif +#ifndef GL_RENDERBUFFER_GREEN_SIZE +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#endif +#ifndef GL_RENDERBUFFER_HEIGHT +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#endif +#ifndef GL_RENDERBUFFER_INTERNAL_FORMAT +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#endif +#ifndef GL_RENDERBUFFER_RED_SIZE +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#endif +#ifndef GL_RENDERBUFFER_STENCIL_SIZE +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#endif +#ifndef GL_RENDERBUFFER_WIDTH +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#endif +#ifndef GL_RENDERER +#define GL_RENDERER 0x1F01 +#endif +#ifndef GL_REPEAT +#define GL_REPEAT 0x2901 +#endif +#ifndef GL_REPLACE +#define GL_REPLACE 0x1E01 +#endif +#ifndef GL_RGB +#define GL_RGB 0x1907 +#endif +#ifndef GL_RGB565 +#define GL_RGB565 0x8D62 +#endif +#ifndef GL_RGB5_A1 +#define GL_RGB5_A1 0x8057 +#endif +#ifndef GL_RGBA +#define GL_RGBA 0x1908 +#endif +#ifndef GL_RGBA4 +#define GL_RGBA4 0x8056 +#endif +#ifndef GL_BGRA +#define GL_BGRA 0x80E1 +#endif +#ifndef GL_SAMPLE_ALPHA_TO_COVERAGE +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#endif +#ifndef GL_SAMPLE_BUFFERS +#define GL_SAMPLE_BUFFERS 0x80A8 +#endif +#ifndef GL_SAMPLE_COVERAGE +#define GL_SAMPLE_COVERAGE 0x80A0 +#endif +#ifndef GL_SAMPLE_COVERAGE_INVERT +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#endif +#ifndef GL_SAMPLE_COVERAGE_VALUE +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#endif +#ifndef GL_SAMPLER_2D +#define GL_SAMPLER_2D 0x8B5E +#endif +#ifndef GL_SAMPLER_CUBE +#define GL_SAMPLER_CUBE 0x8B60 +#endif +#ifndef GL_SAMPLES +#define GL_SAMPLES 0x80A9 +#endif +#ifndef GL_SCISSOR_BOX +#define GL_SCISSOR_BOX 0x0C10 +#endif +#ifndef GL_SCISSOR_TEST +#define GL_SCISSOR_TEST 0x0C11 +#endif +#ifndef GL_SHADER_BINARY_FORMATS +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#endif +#ifndef GL_SHADER_COMPILER +#define GL_SHADER_COMPILER 0x8DFA +#endif +#ifndef GL_SHADER_SOURCE_LENGTH +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#endif +#ifndef GL_SHADER_TYPE +#define GL_SHADER_TYPE 0x8B4F +#endif +#ifndef GL_SHADING_LANGUAGE_VERSION +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#endif +#ifndef GL_SHORT +#define GL_SHORT 0x1402 +#endif +#ifndef GL_SRC_ALPHA +#define GL_SRC_ALPHA 0x0302 +#endif +#ifndef GL_SRC_ALPHA_SATURATE +#define GL_SRC_ALPHA_SATURATE 0x0308 +#endif +#ifndef GL_SRC_COLOR +#define GL_SRC_COLOR 0x0300 +#endif +#ifndef GL_STATIC_DRAW +#define GL_STATIC_DRAW 0x88E4 +#endif +#ifndef GL_STENCIL_ATTACHMENT +#define GL_STENCIL_ATTACHMENT 0x8D20 +#endif +#ifndef GL_STENCIL_BACK_FAIL +#define GL_STENCIL_BACK_FAIL 0x8801 +#endif +#ifndef GL_STENCIL_BACK_FUNC +#define GL_STENCIL_BACK_FUNC 0x8800 +#endif +#ifndef GL_STENCIL_BACK_PASS_DEPTH_FAIL +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#endif +#ifndef GL_STENCIL_BACK_PASS_DEPTH_PASS +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#endif +#ifndef GL_STENCIL_BACK_REF +#define GL_STENCIL_BACK_REF 0x8CA3 +#endif +#ifndef GL_STENCIL_BACK_VALUE_MASK +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#endif +#ifndef GL_STENCIL_BACK_WRITEMASK +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#endif +#ifndef GL_STENCIL_BITS +#define GL_STENCIL_BITS 0x0D57 +#endif +#ifndef GL_STENCIL_BUFFER_BIT +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#endif +#ifndef GL_STENCIL_CLEAR_VALUE +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#endif +#ifndef GL_STENCIL_FAIL +#define GL_STENCIL_FAIL 0x0B94 +#endif +#ifndef GL_STENCIL_FUNC +#define GL_STENCIL_FUNC 0x0B92 +#endif +#ifndef GL_STENCIL_INDEX +#define GL_STENCIL_INDEX 0x1901 +#endif +#ifndef GL_STENCIL_INDEX8 +#define GL_STENCIL_INDEX8 0x8D48 +#endif +#ifndef GL_STENCIL_PASS_DEPTH_FAIL +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#endif +#ifndef GL_STENCIL_PASS_DEPTH_PASS +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#endif +#ifndef GL_STENCIL_REF +#define GL_STENCIL_REF 0x0B97 +#endif +#ifndef GL_STENCIL_TEST +#define GL_STENCIL_TEST 0x0B90 +#endif +#ifndef GL_STENCIL_VALUE_MASK +#define GL_STENCIL_VALUE_MASK 0x0B93 +#endif +#ifndef GL_STENCIL_WRITEMASK +#define GL_STENCIL_WRITEMASK 0x0B98 +#endif +#ifndef GL_STREAM_DRAW +#define GL_STREAM_DRAW 0x88E0 +#endif +#ifndef GL_SUBPIXEL_BITS +#define GL_SUBPIXEL_BITS 0x0D50 +#endif +#ifndef GL_TEXTURE0 +#define GL_TEXTURE0 0x84C0 +#endif +#ifndef GL_TEXTURE +#define GL_TEXTURE 0x1702 +#endif +#ifndef GL_TEXTURE10 +#define GL_TEXTURE10 0x84CA +#endif +#ifndef GL_TEXTURE1 +#define GL_TEXTURE1 0x84C1 +#endif +#ifndef GL_TEXTURE11 +#define GL_TEXTURE11 0x84CB +#endif +#ifndef GL_TEXTURE12 +#define GL_TEXTURE12 0x84CC +#endif +#ifndef GL_TEXTURE13 +#define GL_TEXTURE13 0x84CD +#endif +#ifndef GL_TEXTURE14 +#define GL_TEXTURE14 0x84CE +#endif +#ifndef GL_TEXTURE15 +#define GL_TEXTURE15 0x84CF +#endif +#ifndef GL_TEXTURE16 +#define GL_TEXTURE16 0x84D0 +#endif +#ifndef GL_TEXTURE17 +#define GL_TEXTURE17 0x84D1 +#endif +#ifndef GL_TEXTURE18 +#define GL_TEXTURE18 0x84D2 +#endif +#ifndef GL_TEXTURE19 +#define GL_TEXTURE19 0x84D3 +#endif +#ifndef GL_TEXTURE20 +#define GL_TEXTURE20 0x84D4 +#endif +#ifndef GL_TEXTURE2 +#define GL_TEXTURE2 0x84C2 +#endif +#ifndef GL_TEXTURE21 +#define GL_TEXTURE21 0x84D5 +#endif +#ifndef GL_TEXTURE22 +#define GL_TEXTURE22 0x84D6 +#endif +#ifndef GL_TEXTURE23 +#define GL_TEXTURE23 0x84D7 +#endif +#ifndef GL_TEXTURE24 +#define GL_TEXTURE24 0x84D8 +#endif +#ifndef GL_TEXTURE25 +#define GL_TEXTURE25 0x84D9 +#endif +#ifndef GL_TEXTURE26 +#define GL_TEXTURE26 0x84DA +#endif +#ifndef GL_TEXTURE27 +#define GL_TEXTURE27 0x84DB +#endif +#ifndef GL_TEXTURE28 +#define GL_TEXTURE28 0x84DC +#endif +#ifndef GL_TEXTURE29 +#define GL_TEXTURE29 0x84DD +#endif +#ifndef GL_TEXTURE_2D +#define GL_TEXTURE_2D 0x0DE1 +#endif +#ifndef GL_TEXTURE30 +#define GL_TEXTURE30 0x84DE +#endif +#ifndef GL_TEXTURE3 +#define GL_TEXTURE3 0x84C3 +#endif +#ifndef GL_TEXTURE31 +#define GL_TEXTURE31 0x84DF +#endif +#ifndef GL_TEXTURE4 +#define GL_TEXTURE4 0x84C4 +#endif +#ifndef GL_TEXTURE5 +#define GL_TEXTURE5 0x84C5 +#endif +#ifndef GL_TEXTURE6 +#define GL_TEXTURE6 0x84C6 +#endif +#ifndef GL_TEXTURE7 +#define GL_TEXTURE7 0x84C7 +#endif +#ifndef GL_TEXTURE8 +#define GL_TEXTURE8 0x84C8 +#endif +#ifndef GL_TEXTURE9 +#define GL_TEXTURE9 0x84C9 +#endif +#ifndef GL_TEXTURE_BINDING_2D +#define GL_TEXTURE_BINDING_2D 0x8069 +#endif +#ifndef GL_TEXTURE_BINDING_CUBE_MAP +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#endif +#ifndef GL_TEXTURE_CUBE_MAP +#define GL_TEXTURE_CUBE_MAP 0x8513 +#endif +#ifndef GL_TEXTURE_CUBE_MAP_NEGATIVE_X +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#endif +#ifndef GL_TEXTURE_CUBE_MAP_NEGATIVE_Y +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#endif +#ifndef GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#endif +#ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_X +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#endif +#ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_Y +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#endif +#ifndef GL_TEXTURE_CUBE_MAP_POSITIVE_Z +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#endif +#ifndef GL_TEXTURE_MAG_FILTER +#define GL_TEXTURE_MAG_FILTER 0x2800 +#endif +#ifndef GL_TEXTURE_MIN_FILTER +#define GL_TEXTURE_MIN_FILTER 0x2801 +#endif +#ifndef GL_TEXTURE_WRAP_S +#define GL_TEXTURE_WRAP_S 0x2802 +#endif +#ifndef GL_TEXTURE_WRAP_T +#define GL_TEXTURE_WRAP_T 0x2803 +#endif +#ifndef GL_TRIANGLE_FAN +#define GL_TRIANGLE_FAN 0x0006 +#endif +#ifndef GL_TRIANGLES +#define GL_TRIANGLES 0x0004 +#endif +#ifndef GL_TRIANGLE_STRIP +#define GL_TRIANGLE_STRIP 0x0005 +#endif +#ifndef GL_TRUE +#define GL_TRUE 1 +#endif +#ifndef GL_UNPACK_ALIGNMENT +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#endif +#ifndef GL_UNSIGNED_BYTE +#define GL_UNSIGNED_BYTE 0x1401 +#endif +#ifndef GL_UNSIGNED_INT +#define GL_UNSIGNED_INT 0x1405 +#endif +#ifndef GL_UNSIGNED_SHORT +#define GL_UNSIGNED_SHORT 0x1403 +#endif +#ifndef GL_UNSIGNED_SHORT_4_4_4_4 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#endif +#ifndef GL_UNSIGNED_SHORT_5_5_5_1 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#endif +#ifndef GL_UNSIGNED_SHORT_5_6_5 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 +#endif +#ifndef GL_VALIDATE_STATUS +#define GL_VALIDATE_STATUS 0x8B83 +#endif +#ifndef GL_VENDOR +#define GL_VENDOR 0x1F00 +#endif +#ifndef GL_VERSION +#define GL_VERSION 0x1F02 +#endif +#ifndef GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F +#endif +#ifndef GL_VERTEX_ATTRIB_ARRAY_ENABLED +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#endif +#ifndef GL_VERTEX_ATTRIB_ARRAY_NORMALIZED +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#endif +#ifndef GL_VERTEX_ATTRIB_ARRAY_POINTER +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#endif +#ifndef GL_VERTEX_ATTRIB_ARRAY_SIZE +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#endif +#ifndef GL_VERTEX_ATTRIB_ARRAY_STRIDE +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#endif +#ifndef GL_VERTEX_ATTRIB_ARRAY_TYPE +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#endif +#ifndef GL_VERTEX_SHADER +#define GL_VERTEX_SHADER 0x8B31 +#endif +#ifndef GL_VIEWPORT +#define GL_VIEWPORT 0x0BA2 +#endif +#ifndef GL_ZERO +#define GL_ZERO 0 +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/gui/opengl/qopenglgradientcache.cpp b/src/gui/opengl/qopenglgradientcache.cpp new file mode 100644 index 0000000000..f8d61cd620 --- /dev/null +++ b/src/gui/opengl/qopenglgradientcache.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenglgradientcache_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QOpenGL2GradientCacheWrapper +{ +public: + QOpenGL2GradientCache *cacheForContext(QOpenGLContext *context) { + QMutexLocker lock(&m_mutex); + return m_resource.value(context); + } + +private: + QOpenGLMultiGroupSharedResource m_resource; + QMutex m_mutex; +}; + +Q_GLOBAL_STATIC(QOpenGL2GradientCacheWrapper, qt_gradient_caches) + +QOpenGL2GradientCache::QOpenGL2GradientCache(QOpenGLContext *ctx) + : QOpenGLSharedResource(ctx->shareGroup()) +{ +} + +QOpenGL2GradientCache::~QOpenGL2GradientCache() +{ + cache.clear(); +} + +QOpenGL2GradientCache *QOpenGL2GradientCache::cacheForContext(QOpenGLContext *context) +{ + return qt_gradient_caches()->cacheForContext(context); +} + +void QOpenGL2GradientCache::invalidateResource() +{ + QMutexLocker lock(&m_mutex); + cache.clear(); +} + +void QOpenGL2GradientCache::freeResource(QOpenGLContext *) +{ + cleanCache(); +} + +void QOpenGL2GradientCache::cleanCache() +{ + QMutexLocker lock(&m_mutex); + QOpenGLGradientColorTableHash::const_iterator it = cache.constBegin(); + for (; it != cache.constEnd(); ++it) { + const CacheInfo &cache_info = it.value(); + glDeleteTextures(1, &cache_info.texId); + } + cache.clear(); +} + +GLuint QOpenGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity) +{ + QMutexLocker lock(&m_mutex); + quint64 hash_val = 0; + + QGradientStops stops = gradient.stops(); + for (int i = 0; i < stops.size() && i <= 2; i++) + hash_val += stops[i].second.rgba(); + + QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(hash_val); + + if (it == cache.constEnd()) + return addCacheElement(hash_val, gradient, opacity); + else { + do { + const CacheInfo &cache_info = it.value(); + if (cache_info.stops == stops && cache_info.opacity == opacity + && cache_info.interpolationMode == gradient.interpolationMode()) + { + return cache_info.texId; + } + ++it; + } while (it != cache.constEnd() && it.key() == hash_val); + // an exact match for these stops and opacity was not found, create new cache + return addCacheElement(hash_val, gradient, opacity); + } +} + + +GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) +{ + if (cache.size() == maxCacheSize()) { + int elem_to_remove = qrand() % maxCacheSize(); + quint64 key = cache.keys()[elem_to_remove]; + + // need to call glDeleteTextures on each removed cache entry: + QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key); + do { + glDeleteTextures(1, &it.value().texId); + } while (++it != cache.constEnd() && it.key() == key); + cache.remove(key); // may remove more than 1, but OK + } + + CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode()); + uint buffer[1024]; + generateGradientColorTable(gradient, buffer, paletteSize(), opacity); + glGenTextures(1, &cache_entry.texId); + glBindTexture(GL_TEXTURE_2D, cache_entry.texId); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, paletteSize(), 1, + 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + return cache.insert(hash_val, cache_entry).value().texId; +} + + +// GL's expects pixels in RGBA (when using GL_RGBA), bin-endian (ABGR on x86). +// Qt always stores in ARGB reguardless of the byte-order the mancine uses. +static inline uint qtToGlColor(uint c) +{ + uint o; +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + o = (c & 0xff00ff00) // alpha & green already in the right place + | ((c >> 16) & 0x000000ff) // red + | ((c << 16) & 0x00ff0000); // blue +#else //Q_BIG_ENDIAN + o = (c << 8) + | ((c >> 24) & 0x000000ff); +#endif // Q_BYTE_ORDER + return o; +} + +//TODO: Let GL generate the texture using an FBO +void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const +{ + int pos = 0; + QGradientStops s = gradient.stops(); + QVector colors(s.size()); + + for (int i = 0; i < s.size(); ++i) + colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB (on little-endian AND on big-endian) + + bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); + + uint alpha = qRound(opacity * 256); + uint current_color = ARGB_COMBINE_ALPHA(colors[0], alpha); + qreal incr = 1.0 / qreal(size); + qreal fpos = 1.5 * incr; + colorTable[pos++] = qtToGlColor(PREMUL(current_color)); + + while (fpos <= s.first().first) { + colorTable[pos] = colorTable[pos - 1]; + pos++; + fpos += incr; + } + + if (colorInterpolation) + current_color = PREMUL(current_color); + + for (int i = 0; i < s.size() - 1; ++i) { + qreal delta = 1/(s[i+1].first - s[i].first); + uint next_color = ARGB_COMBINE_ALPHA(colors[i+1], alpha); + if (colorInterpolation) + next_color = PREMUL(next_color); + + while (fpos < s[i+1].first && pos < size) { + int dist = int(256 * ((fpos - s[i].first) * delta)); + int idist = 256 - dist; + if (colorInterpolation) + colorTable[pos] = qtToGlColor(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); + else + colorTable[pos] = qtToGlColor(PREMUL(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist))); + ++pos; + fpos += incr; + } + current_color = next_color; + } + + Q_ASSERT(s.size() > 0); + + uint last_color = qtToGlColor(PREMUL(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha))); + for (;pos < size; ++pos) + colorTable[pos] = last_color; + + // Make sure the last color stop is represented at the end of the table + colorTable[size-1] = last_color; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglgradientcache_p.h b/src/gui/opengl/qopenglgradientcache_p.h new file mode 100644 index 0000000000..53abf221d2 --- /dev/null +++ b/src/gui/opengl/qopenglgradientcache_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QOpenGL2GradientCache : public QOpenGLSharedResource +{ + struct CacheInfo + { + inline CacheInfo(QGradientStops s, qreal op, QGradient::InterpolationMode mode) : + stops(s), opacity(op), interpolationMode(mode) {} + + GLuint texId; + QGradientStops stops; + qreal opacity; + QGradient::InterpolationMode interpolationMode; + }; + + typedef QMultiHash QOpenGLGradientColorTableHash; + +public: + static QOpenGL2GradientCache *cacheForContext(QOpenGLContext *context); + + QOpenGL2GradientCache(QOpenGLContext *); + ~QOpenGL2GradientCache(); + + GLuint getBuffer(const QGradient &gradient, qreal opacity); + inline int paletteSize() const { return 1024; } + + void invalidateResource(); + void freeResource(QOpenGLContext *ctx); + +private: + inline int maxCacheSize() const { return 60; } + inline void generateGradientColorTable(const QGradient& gradient, + uint *colorTable, + int size, qreal opacity) const; + GLuint addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity); + void cleanCache(); + + QOpenGLGradientColorTableHash cache; + QMutex m_mutex; +}; + +QT_END_NAMESPACE + diff --git a/src/gui/opengl/qopenglpaintdevice.cpp b/src/gui/opengl/qopenglpaintdevice.cpp new file mode 100644 index 0000000000..e3ff5ae1f9 --- /dev/null +++ b/src/gui/opengl/qopenglpaintdevice.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +QOpenGLPaintDevice::QOpenGLPaintDevice() + : m_thisFBO(0) +{ +} + +QOpenGLPaintDevice::~QOpenGLPaintDevice() +{ +} + +int QOpenGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + switch(metric) { + case PdmWidth: + return size().width(); + case PdmHeight: + return size().height(); + case PdmDepth: { + const QSurfaceFormat f = format(); + return f.redBufferSize() + f.greenBufferSize() + f.blueBufferSize() + f.alphaBufferSize(); + } + default: + qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric); + return 0; + } +} + +void QOpenGLPaintDevice::beginPaint() +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + + // Record the currently bound FBO so we can restore it again + // in endPaint() and bind this device's FBO + // + // Note: m_thisFBO could be zero if the paint device is not + // backed by an FBO (e.g. window back buffer). But there could + // be a previous FBO bound to the context which we need to + // explicitly unbind. Otherwise the painting will go into + // the previous FBO instead of to the window. + m_previousFBO = ctx->d_func()->current_fbo; + + if (m_previousFBO != m_thisFBO) { + ctx->d_func()->current_fbo = m_thisFBO; + QOpenGLFunctions(ctx).glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO); + } + + // Set the default fbo for the context to m_thisFBO so that + // if some raw GL code between beginNativePainting() and + // endNativePainting() calls QOpenGLFramebufferObject::release(), + // painting will revert to the window surface's fbo. + ctx->d_func()->default_fbo = m_thisFBO; +} + +void QOpenGLPaintDevice::ensureActiveTarget() +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + + if (ctx->d_func()->current_fbo != m_thisFBO) { + ctx->d_func()->current_fbo = m_thisFBO; + QOpenGLFunctions(ctx).glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO); + } + + ctx->d_func()->default_fbo = m_thisFBO; +} + +void QOpenGLPaintDevice::endPaint() +{ + // Make sure the FBO bound at beginPaint is re-bound again here: + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + + if (m_previousFBO != ctx->d_func()->current_fbo) { + ctx->d_func()->current_fbo = m_previousFBO; + QOpenGLFunctions(ctx).glBindFramebuffer(GL_FRAMEBUFFER, m_previousFBO); + } + + ctx->d_func()->default_fbo = 0; +} + +bool QOpenGLPaintDevice::isFlipped() const +{ + return false; +} + +// returns the QOpenGLPaintDevice for the given QPaintDevice +QOpenGLPaintDevice* QOpenGLPaintDevice::getDevice(QPaintDevice* pd) +{ + QOpenGLPaintDevice* glpd = 0; + + switch(pd->devType()) { + case QInternal::FramebufferObject: + glpd = &(static_cast(pd)->d_func()->glDevice); + break; + case QInternal::Pixmap: { + qWarning("Pixmap type not supported for GL rendering"); + break; + } + default: + qWarning("QOpenGLPaintDevice::getDevice() - Unknown device type %d", pd->devType()); + break; + } + + return glpd; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglpaintdevice_p.h b/src/gui/opengl/qopenglpaintdevice_p.h new file mode 100644 index 0000000000..492bc1649a --- /dev/null +++ b/src/gui/opengl/qopenglpaintdevice_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLPAINTDEVICE_P_H +#define QOPENGLPAINTDEVICE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QtGui module. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QOpenGLPaintDevice : public QPaintDevice +{ +public: + QOpenGLPaintDevice(); + virtual ~QOpenGLPaintDevice(); + + int devType() const {return QInternal::OpenGL;} + + virtual void beginPaint(); + virtual void ensureActiveTarget(); + virtual void endPaint(); + + virtual QOpenGLContextGroup *group() const = 0; + + virtual QSurfaceFormat format() const = 0; + virtual QSize size() const = 0; + + virtual bool alphaRequested() const = 0; + virtual bool isFlipped() const; + + // returns the QOpenGLPaintDevice for the given QPaintDevice + static QOpenGLPaintDevice* getDevice(QPaintDevice*); + +protected: + int metric(QPaintDevice::PaintDeviceMetric metric) const; + GLuint m_previousFBO; + GLuint m_thisFBO; +}; + + +#if 0 +// Wraps a QOpenGLWidget +class QOpenGLWidget; +class Q_GUI_EXPORT QOpenGLWidgetGLPaintDevice : public QOpenGLPaintDevice +{ +public: + QOpenGLWidgetGLPaintDevice(); + + virtual QPaintEngine* paintEngine() const; + + // QOpenGLWidgets need to do swapBufers in endPaint: + virtual void beginPaint(); + virtual void endPaint(); + virtual QSize size() const; + virtual QOpenGLContext* context() const; + + void setWidget(QOpenGLWidget*); + +private: + friend class QOpenGLWidget; + QOpenGLWidget *glWidget; +}; +#endif + +QT_END_NAMESPACE + +#endif // QOPENGLPAINTDEVICE_P_H diff --git a/src/gui/opengl/qopenglshadercache_meego_p.h b/src/gui/opengl/qopenglshadercache_meego_p.h new file mode 100644 index 0000000000..86a8a861da --- /dev/null +++ b/src/gui/opengl/qopenglshadercache_meego_p.h @@ -0,0 +1,457 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QOPENGLSHADERCACHE_MEEGO_P_H +#define QOPENGLSHADERCACHE_MEEGO_P_H + +#include + +#if defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE) && defined(QT_OPENGL_ES_2) + +#include +#include +#include + +#ifndef QT_BOOTSTRAPPED +# include +#endif +#if defined(QT_DEBUG) || defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE_TRACE) +# include +#endif + +QT_BEGIN_HEADER + +/* + This cache stores internal Qt shader programs in shared memory. + + This header file is ugly on purpose and can only be included once. It is only to be used + for the internal shader cache, not as a generic cache for anyone's shaders. + + The cache stores either ShaderCacheMaxEntries shader programs or ShaderCacheDataSize kilobytes + of shader programs, whatever limit is reached first. + + The layout of the cache is as outlined in the CachedShaders struct. After some + integers, an array of headers is reserved, then comes the space for the actual binaries. + + Shader Programs are identified by the md5sum of their frag and vertex shader source code. + + Shader Programs are never removed. The cache never shrinks or re-shuffles. This is done + on purpose to ensure minimum amount of locking, no alignment problems and very few write + operations. + + Note: Locking the shader cache could be expensive, because the entire system might hang. + That's why the cache is immutable to minimize the time we need to keep it locked. + + Why is it Meego specific? + + First, the size is chosen so that it fits to generic meego usage. Second, on Meego, there's + always at least one Qt application active (the launcher), so the cache will never be destroyed. + Only when the last Qt app exits, the cache dies, which should only be when someone kills the + X11 server. And last but not least it was only tested with Meego's SGX driver. + + There's a small tool in src/opengl/util/meego that dumps the contents of the cache. + */ + +// anonymous namespace, prevent exporting of the private symbols +namespace +{ + +struct CachedShaderHeader +{ + /* the index in the data[] member of CachedShaders */ + int index; + /* the size of the binary shader */ + GLsizei size; + /* the format of the binary shader */ + GLenum format; + /* the md5sum of the frag+vertex shaders */ + char md5Sum[16]; +}; + +enum +{ + /* The maximum amount of shader programs the cache can hold */ + ShaderCacheMaxEntries = 20 +}; + +typedef CachedShaderHeader CachedShaderHeaders[ShaderCacheMaxEntries]; + +enum +{ + // ShaderCacheDataSize is 20k minus the other data members of CachedShaders + ShaderCacheDataSize = 1024 * ShaderCacheMaxEntries - sizeof(CachedShaderHeaders) - 2 * sizeof(int) +}; + +struct CachedShaders +{ + /* How much space is still available in the cache */ + inline int availableSize() const { return ShaderCacheDataSize - dataSize; } + + /* The current amount of cached shaders */ + int shaderCount; + + /* The current amount (in bytes) of cached data */ + int dataSize; + + /* The headers describing the shaders */ + CachedShaderHeaders headers; + + /* The actual binary data of the shader programs */ + char data[ShaderCacheDataSize]; +}; + +//#define QT_DEBUG_SHADER_CACHE +#ifdef QT_DEBUG_SHADER_CACHE +static QDebug shaderCacheDebug() +{ + return QDebug(QtDebugMsg); +} +#else +static inline QNoDebug shaderCacheDebug() { return QNoDebug(); } +#endif + +class ShaderCacheSharedMemory +{ +public: + ShaderCacheSharedMemory() + : shm(QLatin1String("qt_gles2_shadercache_" QT_VERSION_STR)) + { + // we need a system semaphore here, since cache creation and initialization must be atomic + QSystemSemaphore attachSemaphore(QLatin1String("qt_gles2_shadercache_mutex_" QT_VERSION_STR), 1); + + if (!attachSemaphore.acquire()) { + shaderCacheDebug() << "Unable to require shader cache semaphore:" << attachSemaphore.errorString(); + return; + } + + if (shm.attach()) { + // success! + shaderCacheDebug() << "Attached to shader cache"; + } else { + + // no cache exists - create and initialize it + if (shm.create(sizeof(CachedShaders))) { + shaderCacheDebug() << "Created new shader cache"; + initializeCache(); + } else { + shaderCacheDebug() << "Unable to create shader cache:" << shm.errorString(); + } + } + + attachSemaphore.release(); + } + + inline bool isAttached() const { return shm.isAttached(); } + + inline bool lock() { return shm.lock(); } + inline bool unlock() { return shm.unlock(); } + inline void *data() { return shm.data(); } + inline QString errorString() { return shm.errorString(); } + + ~ShaderCacheSharedMemory() + { + if (!shm.detach()) + shaderCacheDebug() << "Unable to detach shader cache" << shm.errorString(); + } + +private: + void initializeCache() + { + // no need to lock the shared memory since we're already protected by the + // attach system semaphore. + + void *data = shm.data(); + Q_ASSERT(data); + + memset(data, 0, sizeof(CachedShaders)); + } + + QSharedMemory shm; +}; + +class ShaderCacheLocker +{ +public: + inline ShaderCacheLocker(ShaderCacheSharedMemory *cache) + : shm(cache->lock() ? cache : (ShaderCacheSharedMemory *)0) + { + if (!shm) + shaderCacheDebug() << "Unable to lock shader cache" << cache->errorString(); + } + + inline bool isLocked() const { return shm; } + + inline ~ShaderCacheLocker() + { + if (!shm) + return; + if (!shm->unlock()) + shaderCacheDebug() << "Unable to unlock shader cache" << shm->errorString(); + } + +private: + ShaderCacheSharedMemory *shm; +}; + +#ifdef QT_BOOTSTRAPPED +} // end namespace +#else + +static void traceCacheOverflow(const char *message) +{ +#if defined(QT_DEBUG) || defined (QT_MEEGO_EXPERIMENTAL_SHADERCACHE_TRACE) + openlog(qPrintable(QCoreApplication::applicationName()), LOG_PID | LOG_ODELAY, LOG_USER); + syslog(LOG_DEBUG, message); + closelog(); +#endif + shaderCacheDebug() << message; +} + +Q_GLOBAL_STATIC(ShaderCacheSharedMemory, shaderCacheSharedMemory) + +/* + Finds the index of the shader program identified by md5Sum in the cache. + Note: Does NOT lock the cache for reading, the cache must already be locked! + + Returns -1 when no shader was found. + */ +static int qt_cache_index_unlocked(const QByteArray &md5Sum, CachedShaders *cache) +{ + for (int i = 0; i < cache->shaderCount; ++i) { + if (qstrncmp(md5Sum.constData(), cache->headers[i].md5Sum, 16) == 0) { + return i; + } + } + return -1; +} + +/* Returns the index of the shader identified by md5Sum */ +static int qt_cache_index(const QByteArray &md5Sum) +{ + ShaderCacheSharedMemory *shm = shaderCacheSharedMemory(); + if (!shm || !shm->isAttached()) + return false; + + Q_ASSERT(md5Sum.length() == 16); + + ShaderCacheLocker locker(shm); + if (!locker.isLocked()) + return false; + + void *data = shm->data(); + Q_ASSERT(data); + + CachedShaders *cache = reinterpret_cast(data); + + return qt_cache_index_unlocked(md5Sum, cache); +} + +/* Loads the cached shader at index \a shaderIndex into \a program + * Note: Since the cache is immutable, this operation doesn't lock the shared memory. + */ +static bool qt_cached_shader(QOpenGLShaderProgram *program, QOpenGLContext *ctx, int shaderIndex) +{ + Q_ASSERT(shaderIndex >= 0 && shaderIndex <= ShaderCacheMaxEntries); + Q_ASSERT(program); + + ShaderCacheSharedMemory *shm = shaderCacheSharedMemory(); + if (!shm || !shm->isAttached()) + return false; + + void *data = shm->data(); + Q_ASSERT(data); + + CachedShaders *cache = reinterpret_cast(data); + + shaderCacheDebug() << "fetching cached shader at index" << shaderIndex + << "dataIndex" << cache->headers[shaderIndex].index + << "size" << cache->headers[shaderIndex].size + << "format" << cache->headers[shaderIndex].format; + + // call program->programId first, since that resolves the glProgramBinaryOES symbol + GLuint programId = program->programId(); + glProgramBinaryOES(programId, cache->headers[shaderIndex].format, + cache->data + cache->headers[shaderIndex].index, + cache->headers[shaderIndex].size); + + return true; +} + +/* Stores the shader program in the cache. Returns false if there's an error with the cache, or + if the cache is too small to hold the shader. */ +static bool qt_cache_shader(const QOpenGLShaderProgram *shader, QOpenGLContext *ctx, const QByteArray &md5Sum) +{ + ShaderCacheSharedMemory *shm = shaderCacheSharedMemory(); + if (!shm || !shm->isAttached()) + return false; + + void *data = shm->data(); + Q_ASSERT(data); + + CachedShaders *cache = reinterpret_cast(data); + + ShaderCacheLocker locker(shm); + if (!locker.isLocked()) + return false; + + int cacheIdx = cache->shaderCount; + if (cacheIdx >= ShaderCacheMaxEntries) { + traceCacheOverflow("Qt OpenGL shader cache index overflow!"); + return false; + } + + // now that we have the lock on the shared memory, make sure no one + // inserted the shader already while we were unlocked + if (qt_cache_index_unlocked(md5Sum, cache) != -1) + return true; // already cached + + shaderCacheDebug() << "Caching shader at index" << cacheIdx; + + GLint binaryLength = 0; + glGetProgramiv(shader->programId(), GL_PROGRAM_BINARY_LENGTH_OES, &binaryLength); + + if (!binaryLength) { + shaderCacheDebug() << "Unable to determine binary shader size!"; + return false; + } + + if (binaryLength > cache->availableSize()) { + traceCacheOverflow("Qt OpenGL shader cache data overflow!"); + return false; + } + + GLsizei size = 0; + GLenum format = 0; + glGetProgramBinaryOES(shader->programId(), binaryLength, &size, &format, + cache->data + cache->dataSize); + + if (!size) { + shaderCacheDebug() << "Unable to get binary shader!"; + return false; + } + + cache->headers[cacheIdx].index = cache->dataSize; + cache->dataSize += binaryLength; + ++cache->shaderCount; + cache->headers[cacheIdx].size = binaryLength; + cache->headers[cacheIdx].format = format; + + memcpy(cache->headers[cacheIdx].md5Sum, md5Sum.constData(), 16); + + shaderCacheDebug() << "cached shader size" << size + << "format" << format + << "binarySize" << binaryLength + << "cache index" << cacheIdx + << "data index" << cache->headers[cacheIdx].index; + + return true; +} + +} // namespace + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class CachedShader +{ +public: + CachedShader(const QByteArray &fragSource, const QByteArray &vertexSource) + : cacheIdx(-1) + { + QCryptographicHash md5Hash(QCryptographicHash::Md5); + + md5Hash.addData(fragSource); + md5Hash.addData(vertexSource); + + md5Sum = md5Hash.result(); + } + + bool isCached() + { + return cacheIndex() != -1; + } + + int cacheIndex() + { + if (cacheIdx != -1) + return cacheIdx; + cacheIdx = qt_cache_index(md5Sum); + return cacheIdx; + } + + bool load(QOpenGLShaderProgram *program, QOpenGLContext *ctx) + { + if (cacheIndex() == -1) + return false; + return qt_cached_shader(program, ctx, cacheIdx); + } + + bool store(QOpenGLShaderProgram *program, QOpenGLContext *ctx) + { + return qt_cache_shader(program, ctx, md5Sum); + } + +private: + QByteArray md5Sum; + int cacheIdx; +}; + + +QT_END_NAMESPACE + +#endif + +QT_END_HEADER + +#endif +#endif diff --git a/src/opengl/util/meego/main.cpp b/src/gui/opengl/qopenglshadercache_p.h similarity index 58% rename from src/opengl/util/meego/main.cpp rename to src/gui/opengl/qopenglshadercache_p.h index 21ac5fd629..05a058050c 100644 --- a/src/opengl/util/meego/main.cpp +++ b/src/gui/opengl/qopenglshadercache_p.h @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtOpenGL module of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -39,51 +39,60 @@ ** ****************************************************************************/ -#include +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// -#define QT_DEBUG_SHADER_CACHE -#define QT_MEEGO_EXPERIMENTAL_SHADERCACHE -#define QT_OPENGL_ES_2 -#define QT_BOOTSTRAPPED +#ifndef QOPENGLSHADERCACHE_P_H +#define QOPENGLSHADERCACHE_P_H -typedef int GLsizei; -typedef unsigned int GLenum; +#include -#include "../../gl2paintengineex/qglshadercache_meego_p.h" +#if defined(QT_MEEGO_EXPERIMENTAL_SHADERCACHE) && defined(QT_OPENGL_ES_2) +# include "qopenglshadercache_meego_p.h" +#else -#include -#include +QT_BEGIN_HEADER -int main() +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QOpenGLShaderProgram; +class QOpenGLContext; + +class CachedShader { - ShaderCacheSharedMemory shm; +public: + inline CachedShader(const QByteArray &, const QByteArray &) + {} - if (!shm.isAttached()) { - fprintf(stderr, "Unable to attach to shared memory\n"); - return EXIT_FAILURE; + inline bool isCached() + { + return false; } - ShaderCacheLocker locker(&shm); - if (!locker.isLocked()) { - fprintf(stderr, "Unable to lock shared memory\n"); - return EXIT_FAILURE; + inline bool load(QOpenGLShaderProgram *, QOpenGLContext *) + { + return false; } - void *data = shm.data(); - Q_ASSERT(data); - - CachedShaders *cache = reinterpret_cast(data); - - for (int i = 0; i < cache->shaderCount; ++i) { - printf("Shader %d: %d bytes\n", i, cache->headers[i].size); + inline bool store(QOpenGLShaderProgram *, QOpenGLContext *) + { + return false; } +}; - printf("\nSummary:\n\n" - " Amount of cached shaders: %d\n" - " Bytes used: %d\n" - " Bytes available: %d\n", - cache->shaderCount, cache->dataSize, cache->availableSize()); +QT_END_NAMESPACE - return EXIT_SUCCESS; -} +QT_END_HEADER +#endif +#endif diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp new file mode 100644 index 0000000000..a36982162a --- /dev/null +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -0,0 +1,3171 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenglshaderprogram.h" +#include "qopenglfunctions.h" +#include "private/qopenglcontext_p.h" +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QOpenGLShaderProgram + \brief The QOpenGLShaderProgram class allows OpenGL shader programs to be linked and used. + \since 5.0 + \ingroup painting-3D + + \section1 Introduction + + This class supports shader programs written in the OpenGL Shading + Language (GLSL) and in the OpenGL/ES Shading Language (GLSL/ES). + + QOpenGLShader and QOpenGLShaderProgram shelter the programmer from the details of + compiling and linking vertex and fragment shaders. + + The following example creates a vertex shader program using the + supplied source \c{code}. Once compiled and linked, the shader + program is activated in the current QOpenGLContext by calling + QOpenGLShaderProgram::bind(): + + \snippet doc/src/snippets/code/src_opengl_qopenglshaderprogram.cpp 0 + + \section1 Writing portable shaders + + Shader programs can be difficult to reuse across OpenGL implementations + because of varying levels of support for standard vertex attributes and + uniform variables. In particular, GLSL/ES lacks all of the + standard variables that are present on desktop OpenGL systems: + \c{gl_Vertex}, \c{gl_Normal}, \c{gl_Color}, and so on. Desktop OpenGL + lacks the variable qualifiers \c{highp}, \c{mediump}, and \c{lowp}. + + The QOpenGLShaderProgram class makes the process of writing portable shaders + easier by prefixing all shader programs with the following lines on + desktop OpenGL: + + \code + #define highp + #define mediump + #define lowp + \endcode + + This makes it possible to run most GLSL/ES shader programs + on desktop systems. The programmer should restrict themselves + to just features that are present in GLSL/ES, and avoid + standard variable names that only work on the desktop. + + \section1 Simple shader example + + \snippet doc/src/snippets/code/src_opengl_qopenglshaderprogram.cpp 1 + + With the above shader program active, we can draw a green triangle + as follows: + + \snippet doc/src/snippets/code/src_opengl_qopenglshaderprogram.cpp 2 + + \section1 Binary shaders and programs + + Binary shaders may be specified using \c{glShaderBinary()} on + the return value from QOpenGLShader::shaderId(). The QOpenGLShader instance + containing the binary can then be added to the shader program with + addShader() and linked in the usual fashion with link(). + + Binary programs may be specified using \c{glProgramBinaryOES()} + on the return value from programId(). Then the application should + call link(), which will notice that the program has already been + specified and linked, allowing other operations to be performed + on the shader program. + + \sa QOpenGLShader +*/ + +/*! + \class QOpenGLShader + \brief The QOpenGLShader class allows OpenGL shaders to be compiled. + \since 4.6 + \ingroup painting-3D + + This class supports shaders written in the OpenGL Shading Language (GLSL) + and in the OpenGL/ES Shading Language (GLSL/ES). + + QOpenGLShader and QOpenGLShaderProgram shelter the programmer from the details of + compiling and linking vertex and fragment shaders. + + \sa QOpenGLShaderProgram +*/ + +/*! + \enum QOpenGLShader::ShaderTypeBit + This enum specifies the type of QOpenGLShader that is being created. + + \value Vertex Vertex shader written in the OpenGL Shading Language (GLSL). + \value Fragment Fragment shader written in the OpenGL Shading Language (GLSL). + \value Geometry Geometry shaders written in the OpenGL Shading + Language (GLSL), based on the GL_EXT_geometry_shader4 extension. +*/ + +#ifndef GL_FRAGMENT_SHADER +#define GL_FRAGMENT_SHADER 0x8B30 +#endif +#ifndef GL_VERTEX_SHADER +#define GL_VERTEX_SHADER 0x8B31 +#endif +#ifndef GL_COMPILE_STATUS +#define GL_COMPILE_STATUS 0x8B81 +#endif +#ifndef GL_LINK_STATUS +#define GL_LINK_STATUS 0x8B82 +#endif +#ifndef GL_INFO_LOG_LENGTH +#define GL_INFO_LOG_LENGTH 0x8B84 +#endif +#ifndef GL_ACTIVE_UNIFORMS +#define GL_ACTIVE_UNIFORMS 0x8B86 +#endif +#ifndef GL_ACTIVE_UNIFORM_MAX_LENGTH +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#endif +#ifndef GL_ACTIVE_ATTRIBUTES +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#endif +#ifndef GL_ACTIVE_ATTRIBUTE_MAX_LENGTH +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#endif +#ifndef GL_CURRENT_VERTEX_ATTRIB +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#endif +#ifndef GL_SHADER_SOURCE_LENGTH +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#endif +#ifndef GL_SHADER_BINARY_FORMATS +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#endif +#ifndef GL_NUM_SHADER_BINARY_FORMATS +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 +#endif + +class QOpenGLShaderPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QOpenGLShader) +public: + QOpenGLShaderPrivate(QOpenGLContext *ctx, QOpenGLShader::ShaderType type) + : shaderGuard(0) + , shaderType(type) + , compiled(false) + , glfuncs(new QOpenGLFunctions(ctx)) + { + } + ~QOpenGLShaderPrivate(); + + QOpenGLSharedResourceGuard *shaderGuard; + QOpenGLShader::ShaderType shaderType; + bool compiled; + QString log; + + QOpenGLFunctions *glfuncs; + + bool create(); + bool compile(QOpenGLShader *q); + void deleteShader(); +}; + +namespace { + void freeShaderFunc(QOpenGLFunctions *funcs, GLuint id) + { + funcs->glDeleteShader(id); + } +} + +QOpenGLShaderPrivate::~QOpenGLShaderPrivate() +{ + delete glfuncs; + if (shaderGuard) + shaderGuard->free(); +} + +bool QOpenGLShaderPrivate::create() +{ + QOpenGLContext *context = const_cast(QOpenGLContext::currentContext()); + if (!context) + return false; + GLuint shader; + if (shaderType == QOpenGLShader::Vertex) + shader = glfuncs->glCreateShader(GL_VERTEX_SHADER); +#if 0 + else if (shaderType == QOpenGLShader::Geometry) + shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER_EXT); +#endif + else + shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER); + if (!shader) { + qWarning() << "QOpenGLShader: could not create shader"; + return false; + } + shaderGuard = new QOpenGLSharedResourceGuard(context, shader, freeShaderFunc); + return true; +} + +bool QOpenGLShaderPrivate::compile(QOpenGLShader *q) +{ + GLuint shader = shaderGuard ? shaderGuard->id() : 0; + if (!shader) + return false; + glfuncs->glCompileShader(shader); + GLint value = 0; + glfuncs->glGetShaderiv(shader, GL_COMPILE_STATUS, &value); + compiled = (value != 0); + value = 0; + glfuncs->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &value); + if (!compiled && value > 1) { + char *logbuf = new char [value]; + GLint len; + glfuncs->glGetShaderInfoLog(shader, value, &len, logbuf); + log = QString::fromLatin1(logbuf); + QString name = q->objectName(); + + const char *types[] = { + "Fragment", + "Vertex", + "Geometry", + "" + }; + + const char *type = types[3]; + if (shaderType == QOpenGLShader::Fragment) + type = types[0]; + else if (shaderType == QOpenGLShader::Vertex) + type = types[1]; + else if (shaderType == QOpenGLShader::Geometry) + type = types[2]; + + if (name.isEmpty()) + qWarning("QOpenGLShader::compile(%s): %s", type, qPrintable(log)); + else + qWarning("QOpenGLShader::compile(%s)[%s]: %s", type, qPrintable(name), qPrintable(log)); + + delete [] logbuf; + } + return compiled; +} + +void QOpenGLShaderPrivate::deleteShader() +{ + if (shaderGuard) { + shaderGuard->free(); + shaderGuard = 0; + } +} + +/*! + Constructs a new QOpenGLShader object of the specified \a type + and attaches it to \a parent. If shader programs are not supported, + QOpenGLShaderProgram::hasOpenGLShaderPrograms() will return false. + + This constructor is normally followed by a call to compileSourceCode() + or compileSourceFile(). + + The shader will be associated with the current QOpenGLContext. + + \sa compileSourceCode(), compileSourceFile() +*/ +QOpenGLShader::QOpenGLShader(QOpenGLShader::ShaderType type, QObject *parent) + : QObject(*new QOpenGLShaderPrivate(QOpenGLContext::currentContext(), type), parent) +{ + Q_D(QOpenGLShader); + d->create(); +} + +/*! + Deletes this shader. If the shader has been attached to a + QOpenGLShaderProgram object, then the actual shader will stay around + until the QOpenGLShaderProgram is destroyed. +*/ +QOpenGLShader::~QOpenGLShader() +{ +} + +/*! + Returns the type of this shader. +*/ +QOpenGLShader::ShaderType QOpenGLShader::shaderType() const +{ + Q_D(const QOpenGLShader); + return d->shaderType; +} + +// The precision qualifiers are useful on OpenGL/ES systems, +// but usually not present on desktop systems. Define the +// keywords to empty strings on desktop systems. +#if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_FORCE_SHADER_DEFINES) +#define QOpenGL_DEFINE_QUALIFIERS 1 +static const char qualifierDefines[] = + "#define lowp\n" + "#define mediump\n" + "#define highp\n"; + +#else + +// The "highp" qualifier doesn't exist in fragment shaders +// on all ES platforms. When it doesn't exist, use "mediump". +#define QOpenGL_REDEFINE_HIGHP 1 +static const char redefineHighp[] = + "#ifndef GL_FRAGMENT_PRECISION_HIGH\n" + "#define highp mediump\n" + "#endif\n"; +#endif + +/*! + Sets the \a source code for this shader and compiles it. + Returns true if the source was successfully compiled, false otherwise. + + \sa compileSourceFile() +*/ +bool QOpenGLShader::compileSourceCode(const char *source) +{ + Q_D(QOpenGLShader); + if (d->shaderGuard && d->shaderGuard->id()) { + QVarLengthArray src; + QVarLengthArray srclen; + int headerLen = 0; + while (source && source[headerLen] == '#') { + // Skip #version and #extension directives at the start of + // the shader code. We need to insert the qualifierDefines + // and redefineHighp just after them. + if (qstrncmp(source + headerLen, "#version", 8) != 0 && + qstrncmp(source + headerLen, "#extension", 10) != 0) { + break; + } + while (source[headerLen] != '\0' && source[headerLen] != '\n') + ++headerLen; + if (source[headerLen] == '\n') + ++headerLen; + } + if (headerLen > 0) { + src.append(source); + srclen.append(GLint(headerLen)); + } +#ifdef QOpenGL_DEFINE_QUALIFIERS + src.append(qualifierDefines); + srclen.append(GLint(sizeof(qualifierDefines) - 1)); +#endif +#ifdef QOpenGL_REDEFINE_HIGHP + if (d->shaderType == Fragment) { + src.append(redefineHighp); + srclen.append(GLint(sizeof(redefineHighp) - 1)); + } +#endif + src.append(source + headerLen); + srclen.append(GLint(qstrlen(source + headerLen))); + d->glfuncs->glShaderSource(d->shaderGuard->id(), src.size(), src.data(), srclen.data()); + return d->compile(this); + } else { + return false; + } +} + +/*! + \overload + + Sets the \a source code for this shader and compiles it. + Returns true if the source was successfully compiled, false otherwise. + + \sa compileSourceFile() +*/ +bool QOpenGLShader::compileSourceCode(const QByteArray& source) +{ + return compileSourceCode(source.constData()); +} + +/*! + \overload + + Sets the \a source code for this shader and compiles it. + Returns true if the source was successfully compiled, false otherwise. + + \sa compileSourceFile() +*/ +bool QOpenGLShader::compileSourceCode(const QString& source) +{ + return compileSourceCode(source.toLatin1().constData()); +} + +/*! + Sets the source code for this shader to the contents of \a fileName + and compiles it. Returns true if the file could be opened and the + source compiled, false otherwise. + + \sa compileSourceCode() +*/ +bool QOpenGLShader::compileSourceFile(const QString& fileName) +{ + QFile file(fileName); + if (!file.open(QFile::ReadOnly)) { + qWarning() << "QOpenGLShader: Unable to open file" << fileName; + return false; + } + + QByteArray contents = file.readAll(); + return compileSourceCode(contents.constData()); +} + +/*! + Returns the source code for this shader. + + \sa compileSourceCode() +*/ +QByteArray QOpenGLShader::sourceCode() const +{ + Q_D(const QOpenGLShader); + GLuint shader = d->shaderGuard ? d->shaderGuard->id() : 0; + if (!shader) + return QByteArray(); + GLint size = 0; + d->glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &size); + if (size <= 0) + return QByteArray(); + GLint len = 0; + char *source = new char [size]; + d->glfuncs->glGetShaderSource(shader, size, &len, source); + QByteArray src(source); + delete [] source; + return src; +} + +/*! + Returns true if this shader has been compiled; false otherwise. + + \sa compileSourceCode(), compileSourceFile() +*/ +bool QOpenGLShader::isCompiled() const +{ + Q_D(const QOpenGLShader); + return d->compiled; +} + +/*! + Returns the errors and warnings that occurred during the last compile. + + \sa compileSourceCode(), compileSourceFile() +*/ +QString QOpenGLShader::log() const +{ + Q_D(const QOpenGLShader); + return d->log; +} + +/*! + Returns the OpenGL identifier associated with this shader. + + \sa QOpenGLShaderProgram::programId() +*/ +GLuint QOpenGLShader::shaderId() const +{ + Q_D(const QOpenGLShader); + return d->shaderGuard ? d->shaderGuard->id() : 0; +} + +class QOpenGLShaderProgramPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QOpenGLShaderProgram) +public: + QOpenGLShaderProgramPrivate(QOpenGLContext *ctx) + : programGuard(0) + , linked(false) + , inited(false) + , removingShaders(false) + , geometryVertexCount(64) + , geometryInputType(0) + , geometryOutputType(0) + , glfuncs(new QOpenGLFunctions(ctx)) + { + } + ~QOpenGLShaderProgramPrivate(); + + QOpenGLSharedResourceGuard *programGuard; + bool linked; + bool inited; + bool removingShaders; + + int geometryVertexCount; + GLenum geometryInputType; + GLenum geometryOutputType; + + QString log; + QList shaders; + QList anonShaders; + + QOpenGLFunctions *glfuncs; + + bool hasShader(QOpenGLShader::ShaderType type) const; +}; + +namespace { + void freeProgramFunc(QOpenGLFunctions *funcs, GLuint id) + { + funcs->glDeleteProgram(id); + } +} + + +QOpenGLShaderProgramPrivate::~QOpenGLShaderProgramPrivate() +{ + delete glfuncs; + if (programGuard) + programGuard->free(); +} + +bool QOpenGLShaderProgramPrivate::hasShader(QOpenGLShader::ShaderType type) const +{ + foreach (QOpenGLShader *shader, shaders) { + if (shader->shaderType() == type) + return true; + } + return false; +} + +/*! + Constructs a new shader program and attaches it to \a parent. + The program will be invalid until addShader() is called. + + The shader program will be associated with the current QOpenGLContext. + + \sa addShader() +*/ +QOpenGLShaderProgram::QOpenGLShaderProgram(QObject *parent) + : QObject(*new QOpenGLShaderProgramPrivate(QOpenGLContext::currentContext()), parent) +{ +} + +/*! + Deletes this shader program. +*/ +QOpenGLShaderProgram::~QOpenGLShaderProgram() +{ +} + +bool QOpenGLShaderProgram::init() +{ + Q_D(QOpenGLShaderProgram); + if ((d->programGuard && d->programGuard->id()) || d->inited) + return true; + d->inited = true; + QOpenGLContext *context = const_cast(QOpenGLContext::currentContext()); + if (!context) + return false; + GLuint program = d->glfuncs->glCreateProgram(); + if (!program) { + qWarning() << "QOpenGLShaderProgram: could not create shader program"; + return false; + } + if (d->programGuard) + delete d->programGuard; + d->programGuard = new QOpenGLSharedResourceGuard(context, program, freeProgramFunc); + return true; +} + +/*! + Adds a compiled \a shader to this shader program. Returns true + if the shader could be added, or false otherwise. + + Ownership of the \a shader object remains with the caller. + It will not be deleted when this QOpenGLShaderProgram instance + is deleted. This allows the caller to add the same shader + to multiple shader programs. + + \sa addShaderFromSourceCode(), addShaderFromSourceFile() + \sa removeShader(), link(), removeAllShaders() +*/ +bool QOpenGLShaderProgram::addShader(QOpenGLShader *shader) +{ + Q_D(QOpenGLShaderProgram); + if (!init()) + return false; + if (d->shaders.contains(shader)) + return true; // Already added to this shader program. + if (d->programGuard && d->programGuard->id() && shader) { + if (!shader->d_func()->shaderGuard || !shader->d_func()->shaderGuard->id()) + return false; + if (d->programGuard->group() != shader->d_func()->shaderGuard->group()) { + qWarning("QOpenGLShaderProgram::addShader: Program and shader are not associated with same context."); + return false; + } + d->glfuncs->glAttachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); + d->linked = false; // Program needs to be relinked. + d->shaders.append(shader); + connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed())); + return true; + } else { + return false; + } +} + +/*! + Compiles \a source as a shader of the specified \a type and + adds it to this shader program. Returns true if compilation + was successful, false otherwise. The compilation errors + and warnings will be made available via log(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QOpenGLShader first. + + \sa addShader(), addShaderFromSourceFile() + \sa removeShader(), link(), log(), removeAllShaders() +*/ +bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source) +{ + Q_D(QOpenGLShaderProgram); + if (!init()) + return false; + QOpenGLShader *shader = new QOpenGLShader(type, this); + if (!shader->compileSourceCode(source)) { + d->log = shader->log(); + delete shader; + return false; + } + d->anonShaders.append(shader); + return addShader(shader); +} + +/*! + \overload + + Compiles \a source as a shader of the specified \a type and + adds it to this shader program. Returns true if compilation + was successful, false otherwise. The compilation errors + and warnings will be made available via log(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QOpenGLShader first. + + \sa addShader(), addShaderFromSourceFile() + \sa removeShader(), link(), log(), removeAllShaders() +*/ +bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray& source) +{ + return addShaderFromSourceCode(type, source.constData()); +} + +/*! + \overload + + Compiles \a source as a shader of the specified \a type and + adds it to this shader program. Returns true if compilation + was successful, false otherwise. The compilation errors + and warnings will be made available via log(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QOpenGLShader first. + + \sa addShader(), addShaderFromSourceFile() + \sa removeShader(), link(), log(), removeAllShaders() +*/ +bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString& source) +{ + return addShaderFromSourceCode(type, source.toLatin1().constData()); +} + +/*! + Compiles the contents of \a fileName as a shader of the specified + \a type and adds it to this shader program. Returns true if + compilation was successful, false otherwise. The compilation errors + and warnings will be made available via log(). + + This function is intended to be a short-cut for quickly + adding vertex and fragment shaders to a shader program without + creating an instance of QOpenGLShader first. + + \sa addShader(), addShaderFromSourceCode() +*/ +bool QOpenGLShaderProgram::addShaderFromSourceFile + (QOpenGLShader::ShaderType type, const QString& fileName) +{ + Q_D(QOpenGLShaderProgram); + if (!init()) + return false; + QOpenGLShader *shader = new QOpenGLShader(type, this); + if (!shader->compileSourceFile(fileName)) { + d->log = shader->log(); + delete shader; + return false; + } + d->anonShaders.append(shader); + return addShader(shader); +} + +/*! + Removes \a shader from this shader program. The object is not deleted. + + The shader program must be valid in the current QOpenGLContext. + + \sa addShader(), link(), removeAllShaders() +*/ +void QOpenGLShaderProgram::removeShader(QOpenGLShader *shader) +{ + Q_D(QOpenGLShaderProgram); + if (d->programGuard && d->programGuard->id() + && shader && shader->d_func()->shaderGuard) + { + d->glfuncs->glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); + } + d->linked = false; // Program needs to be relinked. + if (shader) { + d->shaders.removeAll(shader); + d->anonShaders.removeAll(shader); + disconnect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed())); + } +} + +/*! + Returns a list of all shaders that have been added to this shader + program using addShader(). + + \sa addShader(), removeShader() +*/ +QList QOpenGLShaderProgram::shaders() const +{ + Q_D(const QOpenGLShaderProgram); + return d->shaders; +} + +/*! + Removes all of the shaders that were added to this program previously. + The QOpenGLShader objects for the shaders will not be deleted if they + were constructed externally. QOpenGLShader objects that are constructed + internally by QOpenGLShaderProgram will be deleted. + + \sa addShader(), removeShader() +*/ +void QOpenGLShaderProgram::removeAllShaders() +{ + Q_D(QOpenGLShaderProgram); + d->removingShaders = true; + foreach (QOpenGLShader *shader, d->shaders) { + if (d->programGuard && d->programGuard->id() + && shader && shader->d_func()->shaderGuard) + { + d->glfuncs->glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); + } + } + foreach (QOpenGLShader *shader, d->anonShaders) { + // Delete shader objects that were created anonymously. + delete shader; + } + d->shaders.clear(); + d->anonShaders.clear(); + d->linked = false; // Program needs to be relinked. + d->removingShaders = false; +} + +/*! + Links together the shaders that were added to this program with + addShader(). Returns true if the link was successful or + false otherwise. If the link failed, the error messages can + be retrieved with log(). + + Subclasses can override this function to initialize attributes + and uniform variables for use in specific shader programs. + + If the shader program was already linked, calling this + function again will force it to be re-linked. + + \sa addShader(), log() +*/ +bool QOpenGLShaderProgram::link() +{ + Q_D(QOpenGLShaderProgram); + GLuint program = d->programGuard ? d->programGuard->id() : 0; + if (!program) + return false; + + GLint value; + if (d->shaders.isEmpty()) { + // If there are no explicit shaders, then it is possible that the + // application added a program binary with glProgramBinaryOES(), + // or otherwise populated the shaders itself. Check to see if the + // program is already linked and bail out if so. + value = 0; + d->glfuncs->glGetProgramiv(program, GL_LINK_STATUS, &value); + d->linked = (value != 0); + if (d->linked) + return true; + } + + // Set up the geometry shader parameters +#if 0 + if (glProgramParameteriEXT) { + foreach (QOpenGLShader *shader, d->shaders) { + if (shader->shaderType() & QOpenGLShader::Geometry) { + glProgramParameteriEXT(program, GL_GEOMETRY_INPUT_TYPE_EXT, + d->geometryInputType); + glProgramParameteriEXT(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, + d->geometryOutputType); + glProgramParameteriEXT(program, GL_GEOMETRY_VERTICES_OUT_EXT, + d->geometryVertexCount); + break; + } + } + } +#endif + + d->glfuncs->glLinkProgram(program); + value = 0; + d->glfuncs->glGetProgramiv(program, GL_LINK_STATUS, &value); + d->linked = (value != 0); + value = 0; + d->glfuncs->glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value); + d->log = QString(); + if (value > 1) { + char *logbuf = new char [value]; + GLint len; + d->glfuncs->glGetProgramInfoLog(program, value, &len, logbuf); + d->log = QString::fromLatin1(logbuf); + QString name = objectName(); + if (name.isEmpty()) + qWarning() << "QOpenGLShader::link:" << d->log; + else + qWarning() << "QOpenGLShader::link[" << name << "]:" << d->log; + delete [] logbuf; + } + return d->linked; +} + +/*! + Returns true if this shader program has been linked; false otherwise. + + \sa link() +*/ +bool QOpenGLShaderProgram::isLinked() const +{ + Q_D(const QOpenGLShaderProgram); + return d->linked; +} + +/*! + Returns the errors and warnings that occurred during the last link() + or addShader() with explicitly specified source code. + + \sa link() +*/ +QString QOpenGLShaderProgram::log() const +{ + Q_D(const QOpenGLShaderProgram); + return d->log; +} + +/*! + Binds this shader program to the active QOpenGLContext and makes + it the current shader program. Any previously bound shader program + is released. This is equivalent to calling \c{glUseProgram()} on + programId(). Returns true if the program was successfully bound; + false otherwise. If the shader program has not yet been linked, + or it needs to be re-linked, this function will call link(). + + \sa link(), release() +*/ +bool QOpenGLShaderProgram::bind() +{ + Q_D(QOpenGLShaderProgram); + GLuint program = d->programGuard ? d->programGuard->id() : 0; + if (!program) + return false; + if (!d->linked && !link()) + return false; +#ifndef QT_NO_DEBUG + if (d->programGuard->group() != QOpenGLContextGroup::currentContextGroup()) { + qWarning("QOpenGLShaderProgram::bind: program is not valid in the current context."); + return false; + } +#endif + d->glfuncs->glUseProgram(program); + return true; +} + +/*! + Releases the active shader program from the current QOpenGLContext. + This is equivalent to calling \c{glUseProgram(0)}. + + \sa bind() +*/ +void QOpenGLShaderProgram::release() +{ +#ifndef QT_NO_DEBUG + Q_D(QOpenGLShaderProgram); + if (d->programGuard->group() != QOpenGLContextGroup::currentContextGroup()) + qWarning("QOpenGLShaderProgram::release: program is not valid in the current context."); +#endif + d->glfuncs->glUseProgram(0); +} + +/*! + Returns the OpenGL identifier associated with this shader program. + + \sa QOpenGLShader::shaderId() +*/ +GLuint QOpenGLShaderProgram::programId() const +{ + Q_D(const QOpenGLShaderProgram); + GLuint id = d->programGuard ? d->programGuard->id() : 0; + if (id) + return id; + + // Create the identifier if we don't have one yet. This is for + // applications that want to create the attached shader configuration + // themselves, particularly those using program binaries. + if (!const_cast(this)->init()) + return 0; + return d->programGuard ? d->programGuard->id() : 0; +} + +/*! + Binds the attribute \a name to the specified \a location. This + function can be called before or after the program has been linked. + Any attributes that have not been explicitly bound when the program + is linked will be assigned locations automatically. + + When this function is called after the program has been linked, + the program will need to be relinked for the change to take effect. + + \sa attributeLocation() +*/ +void QOpenGLShaderProgram::bindAttributeLocation(const char *name, int location) +{ + Q_D(QOpenGLShaderProgram); + if (!init() || !d->programGuard || !d->programGuard->id()) + return; + d->glfuncs->glBindAttribLocation(d->programGuard->id(), location, name); + d->linked = false; // Program needs to be relinked. +} + +/*! + \overload + + Binds the attribute \a name to the specified \a location. This + function can be called before or after the program has been linked. + Any attributes that have not been explicitly bound when the program + is linked will be assigned locations automatically. + + When this function is called after the program has been linked, + the program will need to be relinked for the change to take effect. + + \sa attributeLocation() +*/ +void QOpenGLShaderProgram::bindAttributeLocation(const QByteArray& name, int location) +{ + bindAttributeLocation(name.constData(), location); +} + +/*! + \overload + + Binds the attribute \a name to the specified \a location. This + function can be called before or after the program has been linked. + Any attributes that have not been explicitly bound when the program + is linked will be assigned locations automatically. + + When this function is called after the program has been linked, + the program will need to be relinked for the change to take effect. + + \sa attributeLocation() +*/ +void QOpenGLShaderProgram::bindAttributeLocation(const QString& name, int location) +{ + bindAttributeLocation(name.toLatin1().constData(), location); +} + +/*! + Returns the location of the attribute \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + attribute for this shader program. + + \sa uniformLocation(), bindAttributeLocation() +*/ +int QOpenGLShaderProgram::attributeLocation(const char *name) const +{ + Q_D(const QOpenGLShaderProgram); + if (d->linked && d->programGuard && d->programGuard->id()) { + return d->glfuncs->glGetAttribLocation(d->programGuard->id(), name); + } else { + qWarning() << "QOpenGLShaderProgram::attributeLocation(" << name + << "): shader program is not linked"; + return -1; + } +} + +/*! + \overload + + Returns the location of the attribute \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + attribute for this shader program. + + \sa uniformLocation(), bindAttributeLocation() +*/ +int QOpenGLShaderProgram::attributeLocation(const QByteArray& name) const +{ + return attributeLocation(name.constData()); +} + +/*! + \overload + + Returns the location of the attribute \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + attribute for this shader program. + + \sa uniformLocation(), bindAttributeLocation() +*/ +int QOpenGLShaderProgram::attributeLocation(const QString& name) const +{ + return attributeLocation(name.toLatin1().constData()); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(int location, GLfloat value) +{ + Q_D(QOpenGLShaderProgram); + if (location != -1) + d->glfuncs->glVertexAttrib1fv(location, &value); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(const char *name, GLfloat value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to + the 2D vector (\a x, \a y). + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(int location, GLfloat x, GLfloat y) +{ + Q_D(QOpenGLShaderProgram); + if (location != -1) { + GLfloat values[2] = {x, y}; + d->glfuncs->glVertexAttrib2fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to + the 2D vector (\a x, \a y). + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(const char *name, GLfloat x, GLfloat y) +{ + setAttributeValue(attributeLocation(name), x, y); +} + +/*! + Sets the attribute at \a location in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue + (int location, GLfloat x, GLfloat y, GLfloat z) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat values[3] = {x, y, z}; + d->glfuncs->glVertexAttrib3fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue + (const char *name, GLfloat x, GLfloat y, GLfloat z) +{ + setAttributeValue(attributeLocation(name), x, y, z); +} + +/*! + Sets the attribute at \a location in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue + (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + Q_D(QOpenGLShaderProgram); + if (location != -1) { + GLfloat values[4] = {x, y, z, w}; + d->glfuncs->glVertexAttrib4fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue + (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + setAttributeValue(attributeLocation(name), x, y, z, w); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(int location, const QVector2D& value) +{ + Q_D(QOpenGLShaderProgram); + if (location != -1) + d->glfuncs->glVertexAttrib2fv(location, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector2D& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(int location, const QVector3D& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glVertexAttrib3fv(location, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector3D& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(int location, const QVector4D& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glVertexAttrib4fv(location, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector4D& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to \a value. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(int location, const QColor& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat values[4] = {GLfloat(value.redF()), GLfloat(value.greenF()), + GLfloat(value.blueF()), GLfloat(value.alphaF())}; + d->glfuncs->glVertexAttrib4fv(location, values); + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to \a value. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue(const char *name, const QColor& value) +{ + setAttributeValue(attributeLocation(name), value); +} + +/*! + Sets the attribute at \a location in the current context to the + contents of \a values, which contains \a columns elements, each + consisting of \a rows elements. The \a rows value should be + 1, 2, 3, or 4. This function is typically used to set matrix + values and column vectors. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue + (int location, const GLfloat *values, int columns, int rows) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (rows < 1 || rows > 4) { + qWarning() << "QOpenGLShaderProgram::setAttributeValue: rows" << rows << "not supported"; + return; + } + if (location != -1) { + while (columns-- > 0) { + if (rows == 1) + d->glfuncs->glVertexAttrib1fv(location, values); + else if (rows == 2) + d->glfuncs->glVertexAttrib2fv(location, values); + else if (rows == 3) + d->glfuncs->glVertexAttrib3fv(location, values); + else + d->glfuncs->glVertexAttrib4fv(location, values); + values += rows; + ++location; + } + } +} + +/*! + \overload + + Sets the attribute called \a name in the current context to the + contents of \a values, which contains \a columns elements, each + consisting of \a rows elements. The \a rows value should be + 1, 2, 3, or 4. This function is typically used to set matrix + values and column vectors. + + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::setAttributeValue + (const char *name, const GLfloat *values, int columns, int rows) +{ + setAttributeValue(attributeLocation(name), values, columns, rows); +} + +/*! + Sets an array of vertex \a values on the attribute at \a location + in this shader program. The \a tupleSize indicates the number of + components per vertex (1, 2, 3, or 4), and the \a stride indicates + the number of bytes between vertices. A default \a stride value + of zero indicates that the vertices are densely packed in \a values. + + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() +*/ +void QOpenGLShaderProgram::setAttributeArray + (int location, const GLfloat *values, int tupleSize, int stride) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + d->glfuncs->glVertexAttribPointer(location, tupleSize, GL_FLOAT, GL_FALSE, + stride, values); + } +} + +/*! + Sets an array of 2D vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() +*/ +void QOpenGLShaderProgram::setAttributeArray + (int location, const QVector2D *values, int stride) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + d->glfuncs->glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, + stride, values); + } +} + +/*! + Sets an array of 3D vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() +*/ +void QOpenGLShaderProgram::setAttributeArray + (int location, const QVector3D *values, int stride) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + d->glfuncs->glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, + stride, values); + } +} + +/*! + Sets an array of 4D vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() +*/ +void QOpenGLShaderProgram::setAttributeArray + (int location, const QVector4D *values, int stride) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + d->glfuncs->glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, + stride, values); + } +} + +/*! + Sets an array of vertex \a values on the attribute at \a location + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + The \a type indicates the type of elements in the \a values array, + usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a tupleSize + indicates the number of components per vertex: 1, 2, 3, or 4. + + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + The setAttributeBuffer() function can be used to set the attribute + array to an offset within a vertex buffer. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray(), setAttributeBuffer() + \since 4.7 +*/ +void QOpenGLShaderProgram::setAttributeArray + (int location, GLenum type, const void *values, int tupleSize, int stride) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + d->glfuncs->glVertexAttribPointer(location, tupleSize, type, GL_TRUE, + stride, values); + } +} + +/*! + \overload + + Sets an array of vertex \a values on the attribute called \a name + in this shader program. The \a tupleSize indicates the number of + components per vertex (1, 2, 3, or 4), and the \a stride indicates + the number of bytes between vertices. A default \a stride value + of zero indicates that the vertices are densely packed in \a values. + + The array will become active when enableAttributeArray() is called + on \a name. Otherwise the value specified with setAttributeValue() + for \a name will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() +*/ +void QOpenGLShaderProgram::setAttributeArray + (const char *name, const GLfloat *values, int tupleSize, int stride) +{ + setAttributeArray(attributeLocation(name), values, tupleSize, stride); +} + +/*! + \overload + + Sets an array of 2D vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + The array will become active when enableAttributeArray() is called + on \a name. Otherwise the value specified with setAttributeValue() + for \a name will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() +*/ +void QOpenGLShaderProgram::setAttributeArray + (const char *name, const QVector2D *values, int stride) +{ + setAttributeArray(attributeLocation(name), values, stride); +} + +/*! + \overload + + Sets an array of 3D vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + The array will become active when enableAttributeArray() is called + on \a name. Otherwise the value specified with setAttributeValue() + for \a name will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() +*/ +void QOpenGLShaderProgram::setAttributeArray + (const char *name, const QVector3D *values, int stride) +{ + setAttributeArray(attributeLocation(name), values, stride); +} + +/*! + \overload + + Sets an array of 4D vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + The array will become active when enableAttributeArray() is called + on \a name. Otherwise the value specified with setAttributeValue() + for \a name will be used. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray() +*/ +void QOpenGLShaderProgram::setAttributeArray + (const char *name, const QVector4D *values, int stride) +{ + setAttributeArray(attributeLocation(name), values, stride); +} + +/*! + \overload + + Sets an array of vertex \a values on the attribute called \a name + in this shader program. The \a stride indicates the number of bytes + between vertices. A default \a stride value of zero indicates that + the vertices are densely packed in \a values. + + The \a type indicates the type of elements in the \a values array, + usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a tupleSize + indicates the number of components per vertex: 1, 2, 3, or 4. + + The array will become active when enableAttributeArray() is called + on the \a name. Otherwise the value specified with + setAttributeValue() for \a name will be used. + + The setAttributeBuffer() function can be used to set the attribute + array to an offset within a vertex buffer. + + \sa setAttributeValue(), setUniformValue(), enableAttributeArray() + \sa disableAttributeArray(), setAttributeBuffer() + \since 4.7 +*/ +void QOpenGLShaderProgram::setAttributeArray + (const char *name, GLenum type, const void *values, int tupleSize, int stride) +{ + setAttributeArray(attributeLocation(name), type, values, tupleSize, stride); +} + +/*! + Sets an array of vertex values on the attribute at \a location in + this shader program, starting at a specific \a offset in the + currently bound vertex buffer. The \a stride indicates the number + of bytes between vertices. A default \a stride value of zero + indicates that the vertices are densely packed in the value array. + + The \a type indicates the type of elements in the vertex value + array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a + tupleSize indicates the number of components per vertex: 1, 2, 3, + or 4. + + The array will become active when enableAttributeArray() is called + on the \a location. Otherwise the value specified with + setAttributeValue() for \a location will be used. + + \sa setAttributeArray() + \since 4.7 +*/ +void QOpenGLShaderProgram::setAttributeBuffer + (int location, GLenum type, int offset, int tupleSize, int stride) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + d->glfuncs->glVertexAttribPointer(location, tupleSize, type, GL_TRUE, stride, + reinterpret_cast(offset)); + } +} + +/*! + \overload + + Sets an array of vertex values on the attribute called \a name + in this shader program, starting at a specific \a offset in the + currently bound vertex buffer. The \a stride indicates the number + of bytes between vertices. A default \a stride value of zero + indicates that the vertices are densely packed in the value array. + + The \a type indicates the type of elements in the vertex value + array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a + tupleSize indicates the number of components per vertex: 1, 2, 3, + or 4. + + The array will become active when enableAttributeArray() is called + on the \a name. Otherwise the value specified with + setAttributeValue() for \a name will be used. + + \sa setAttributeArray() + \since 4.7 +*/ +void QOpenGLShaderProgram::setAttributeBuffer + (const char *name, GLenum type, int offset, int tupleSize, int stride) +{ + setAttributeBuffer(attributeLocation(name), type, offset, tupleSize, stride); +} + +/*! + Enables the vertex array at \a location in this shader program + so that the value set by setAttributeArray() on \a location + will be used by the shader program. + + \sa disableAttributeArray(), setAttributeArray(), setAttributeValue() + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::enableAttributeArray(int location) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glEnableVertexAttribArray(location); +} + +/*! + \overload + + Enables the vertex array called \a name in this shader program + so that the value set by setAttributeArray() on \a name + will be used by the shader program. + + \sa disableAttributeArray(), setAttributeArray(), setAttributeValue() + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::enableAttributeArray(const char *name) +{ + enableAttributeArray(attributeLocation(name)); +} + +/*! + Disables the vertex array at \a location in this shader program + that was enabled by a previous call to enableAttributeArray(). + + \sa enableAttributeArray(), setAttributeArray(), setAttributeValue() + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::disableAttributeArray(int location) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glDisableVertexAttribArray(location); +} + +/*! + \overload + + Disables the vertex array called \a name in this shader program + that was enabled by a previous call to enableAttributeArray(). + + \sa enableAttributeArray(), setAttributeArray(), setAttributeValue() + \sa setUniformValue() +*/ +void QOpenGLShaderProgram::disableAttributeArray(const char *name) +{ + disableAttributeArray(attributeLocation(name)); +} + +/*! + Returns the location of the uniform variable \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + uniform variable for this shader program. + + \sa attributeLocation() +*/ +int QOpenGLShaderProgram::uniformLocation(const char *name) const +{ + Q_D(const QOpenGLShaderProgram); + Q_UNUSED(d); + if (d->linked && d->programGuard && d->programGuard->id()) { + return d->glfuncs->glGetUniformLocation(d->programGuard->id(), name); + } else { + qWarning() << "QOpenGLShaderProgram::uniformLocation(" << name + << "): shader program is not linked"; + return -1; + } +} + +/*! + \overload + + Returns the location of the uniform variable \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + uniform variable for this shader program. + + \sa attributeLocation() +*/ +int QOpenGLShaderProgram::uniformLocation(const QByteArray& name) const +{ + return uniformLocation(name.constData()); +} + +/*! + \overload + + Returns the location of the uniform variable \a name within this shader + program's parameter list. Returns -1 if \a name is not a valid + uniform variable for this shader program. + + \sa attributeLocation() +*/ +int QOpenGLShaderProgram::uniformLocation(const QString& name) const +{ + return uniformLocation(name.toLatin1().constData()); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, GLfloat value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform1fv(location, 1, &value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, GLfloat value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, GLint value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform1i(location, value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, GLint value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + This function should be used when setting sampler values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, GLuint value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform1i(location, value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. This function should be used when setting sampler values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, GLuint value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to + the 2D vector (\a x, \a y). + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, GLfloat x, GLfloat y) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat values[2] = {x, y}; + d->glfuncs->glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the 2D vector (\a x, \a y). + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, GLfloat x, GLfloat y) +{ + setUniformValue(uniformLocation(name), x, y); +} + +/*! + Sets the uniform variable at \a location in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue + (int location, GLfloat x, GLfloat y, GLfloat z) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat values[3] = {x, y, z}; + d->glfuncs->glUniform3fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the 3D vector (\a x, \a y, \a z). + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue + (const char *name, GLfloat x, GLfloat y, GLfloat z) +{ + setUniformValue(uniformLocation(name), x, y, z); +} + +/*! + Sets the uniform variable at \a location in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue + (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat values[4] = {x, y, z, w}; + d->glfuncs->glUniform4fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the 4D vector (\a x, \a y, \a z, \a w). + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue + (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + setUniformValue(uniformLocation(name), x, y, z, w); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QVector2D& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform2fv(location, 1, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector2D& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QVector3D& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform3fv(location, 1, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector3D& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QVector4D& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform4fv(location, 1, reinterpret_cast(&value)); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector4D& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to + the red, green, blue, and alpha components of \a color. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QColor& color) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat values[4] = {GLfloat(color.redF()), GLfloat(color.greenF()), + GLfloat(color.blueF()), GLfloat(color.alphaF())}; + d->glfuncs->glUniform4fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to + the red, green, blue, and alpha components of \a color. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QColor& color) +{ + setUniformValue(uniformLocation(name), color); +} + +/*! + Sets the uniform variable at \a location in the current context to + the x and y coordinates of \a point. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QPoint& point) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())}; + d->glfuncs->glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable associated with \a name in the current + context to the x and y coordinates of \a point. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QPoint& point) +{ + setUniformValue(uniformLocation(name), point); +} + +/*! + Sets the uniform variable at \a location in the current context to + the x and y coordinates of \a point. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QPointF& point) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())}; + d->glfuncs->glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable associated with \a name in the current + context to the x and y coordinates of \a point. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QPointF& point) +{ + setUniformValue(uniformLocation(name), point); +} + +/*! + Sets the uniform variable at \a location in the current context to + the width and height of the given \a size. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QSize& size) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.height())}; + d->glfuncs->glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable associated with \a name in the current + context to the width and height of the given \a size. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QSize& size) +{ + setUniformValue(uniformLocation(name), size); +} + +/*! + Sets the uniform variable at \a location in the current context to + the width and height of the given \a size. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QSizeF& size) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.height())}; + d->glfuncs->glUniform2fv(location, 1, values); + } +} + +/*! + \overload + + Sets the uniform variable associated with \a name in the current + context to the width and height of the given \a size. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QSizeF& size) +{ + setUniformValue(uniformLocation(name), size); +} + +// We have to repack matrices from qreal to GLfloat. +#define setUniformMatrix(func,location,value,cols,rows) \ + if (location == -1) \ + return; \ + if (sizeof(qreal) == sizeof(GLfloat)) { \ + func(location, 1, GL_FALSE, \ + reinterpret_cast(value.constData())); \ + } else { \ + GLfloat mat[cols * rows]; \ + const qreal *data = value.constData(); \ + for (int i = 0; i < cols * rows; ++i) \ + mat[i] = data[i]; \ + func(location, 1, GL_FALSE, mat); \ + } +#define setUniformGenericMatrix(colfunc,location,value,cols,rows) \ + if (location == -1) \ + return; \ + if (sizeof(qreal) == sizeof(GLfloat)) { \ + const GLfloat *data = reinterpret_cast \ + (value.constData()); \ + colfunc(location, cols, data); \ + } else { \ + GLfloat mat[cols * rows]; \ + const qreal *data = value.constData(); \ + for (int i = 0; i < cols * rows; ++i) \ + mat[i] = data[i]; \ + colfunc(location, cols, mat); \ + } + +/*! + Sets the uniform variable at \a location in the current context + to a 2x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x2& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformMatrix(d->glfuncs->glUniformMatrix2fv, location, value, 2, 2); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x2& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 2x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x3& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrix + (d->glfuncs->glUniform3fv, location, value, 2, 3); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x3& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 2x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x4& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrix + (d->glfuncs->glUniform4fv, location, value, 2, 4); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x4& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 3x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x2& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrix + (d->glfuncs->glUniform2fv, location, value, 3, 2); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x2& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 3x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x3& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformMatrix(d->glfuncs->glUniformMatrix3fv, location, value, 3, 3); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x3& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 3x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x4& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrix + (d->glfuncs->glUniform4fv, location, value, 3, 4); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x4& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 4x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x2& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrix + (d->glfuncs->glUniform2fv, location, value, 4, 2); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x2 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x2& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 4x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x3& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrix + (d->glfuncs->glUniform3fv, location, value, 4, 3); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x3 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x3& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context + to a 4x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x4& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformMatrix(d->glfuncs->glUniformMatrix4fv, location, value, 4, 4); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x4 matrix \a value. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x4& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + \overload + + Sets the uniform variable at \a location in the current context + to a 2x2 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() + \since 4.7 +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[2][2]) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniformMatrix2fv(location, 1, GL_FALSE, value[0]); +} + +/*! + \overload + + Sets the uniform variable at \a location in the current context + to a 3x3 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() + \since 4.7 +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[3][3]) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, value[0]); +} + +/*! + \overload + + Sets the uniform variable at \a location in the current context + to a 4x4 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[4][4]) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniformMatrix4fv(location, 1, GL_FALSE, value[0]); +} + + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 2x2 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() + \since 4.7 +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[2][2]) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 3x3 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() + \since 4.7 +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[3][3]) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context + to a 4x4 matrix \a value. The matrix elements must be specified + in column-major order. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[4][4]) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable at \a location in the current context to a + 3x3 transformation matrix \a value that is specified as a QTransform value. + + To set a QTransform value as a 4x4 matrix in a shader, use + \c{setUniformValue(location, QMatrix4x4(value))}. +*/ +void QOpenGLShaderProgram::setUniformValue(int location, const QTransform& value) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + GLfloat mat[3][3] = { + {GLfloat(value.m11()), GLfloat(value.m12()), GLfloat(value.m13())}, + {GLfloat(value.m21()), GLfloat(value.m22()), GLfloat(value.m23())}, + {GLfloat(value.m31()), GLfloat(value.m32()), GLfloat(value.m33())} + }; + d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, mat[0]); + } +} + +/*! + \overload + + Sets the uniform variable called \a name in the current context to a + 3x3 transformation matrix \a value that is specified as a QTransform value. + + To set a QTransform value as a 4x4 matrix in a shader, use + \c{setUniformValue(name, QMatrix4x4(value))}. +*/ +void QOpenGLShaderProgram::setUniformValue + (const char *name, const QTransform& value) +{ + setUniformValue(uniformLocation(name), value); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const GLint *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform1iv(location, count, values); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray + (const char *name, const GLint *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count elements of \a values. This overload + should be used when setting an array of sampler values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const GLuint *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform1iv(location, count, reinterpret_cast(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count elements of \a values. This overload + should be used when setting an array of sampler values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray + (const char *name, const GLuint *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count elements of \a values. Each element + has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) { + if (tupleSize == 1) + d->glfuncs->glUniform1fv(location, count, values); + else if (tupleSize == 2) + d->glfuncs->glUniform2fv(location, count, values); + else if (tupleSize == 3) + d->glfuncs->glUniform3fv(location, count, values); + else if (tupleSize == 4) + d->glfuncs->glUniform4fv(location, count, values); + else + qWarning() << "QOpenGLShaderProgram::setUniformValue: size" << tupleSize << "not supported"; + } +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count elements of \a values. Each element + has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray + (const char *name, const GLfloat *values, int count, int tupleSize) +{ + setUniformValueArray(uniformLocation(name), values, count, tupleSize); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector2D *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform2fv(location, count, reinterpret_cast(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector2D *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector3D *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform3fv(location, count, reinterpret_cast(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector3D *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector4D *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + if (location != -1) + d->glfuncs->glUniform4fv(location, count, reinterpret_cast(values)); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4D vector elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +// We have to repack matrix arrays from qreal to GLfloat. +#define setUniformMatrixArray(func,location,values,count,type,cols,rows) \ + if (location == -1 || count <= 0) \ + return; \ + if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \ + func(location, count, GL_FALSE, \ + reinterpret_cast(values[0].constData())); \ + } else { \ + QVarLengthArray temp(cols * rows * count); \ + for (int index = 0; index < count; ++index) { \ + for (int index2 = 0; index2 < (cols * rows); ++index2) { \ + temp.data()[cols * rows * index + index2] = \ + values[index].constData()[index2]; \ + } \ + } \ + func(location, count, GL_FALSE, temp.constData()); \ + } +#define setUniformGenericMatrixArray(colfunc,location,values,count,type,cols,rows) \ + if (location == -1 || count <= 0) \ + return; \ + if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \ + const GLfloat *data = reinterpret_cast \ + (values[0].constData()); \ + colfunc(location, count * cols, data); \ + } else { \ + QVarLengthArray temp(cols * rows * count); \ + for (int index = 0; index < count; ++index) { \ + for (int index2 = 0; index2 < (cols * rows); ++index2) { \ + temp.data()[cols * rows * index + index2] = \ + values[index].constData()[index2]; \ + } \ + } \ + colfunc(location, count * cols, temp.constData()); \ + } + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x2 *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformMatrixArray + (d->glfuncs->glUniformMatrix2fv, location, values, count, QMatrix2x2, 2, 2); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x2 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x3 *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrixArray + (d->glfuncs->glUniform3fv, location, values, count, + QMatrix2x3, 2, 3); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x3 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 2x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x4 *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrixArray + (d->glfuncs->glUniform4fv, location, values, count, + QMatrix2x4, 2, 4); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 2x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x4 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x2 *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrixArray + (d->glfuncs->glUniform2fv, location, values, count, + QMatrix3x2, 3, 2); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x2 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x3 *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformMatrixArray + (d->glfuncs->glUniformMatrix3fv, location, values, count, QMatrix3x3, 3, 3); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x3 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 3x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x4 *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrixArray + (d->glfuncs->glUniform4fv, location, values, count, + QMatrix3x4, 3, 4); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 3x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x4 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x2 *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrixArray + (d->glfuncs->glUniform2fv, location, values, count, + QMatrix4x2, 4, 2); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4x2 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x2 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x3 *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformGenericMatrixArray + (d->glfuncs->glUniform3fv, location, values, count, + QMatrix4x3, 4, 3); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4x3 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x3 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +/*! + Sets the uniform variable array at \a location in the current + context to the \a count 4x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x4 *values, int count) +{ + Q_D(QOpenGLShaderProgram); + Q_UNUSED(d); + setUniformMatrixArray + (d->glfuncs->glUniformMatrix4fv, location, values, count, QMatrix4x4, 4, 4); +} + +/*! + \overload + + Sets the uniform variable array called \a name in the current + context to the \a count 4x4 matrix elements of \a values. + + \sa setAttributeValue() +*/ +void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 *values, int count) +{ + setUniformValueArray(uniformLocation(name), values, count); +} + +#undef ctx + +/*! + Returns the hardware limit for how many vertices a geometry shader + can output. + + \since 4.7 + + \sa setGeometryOutputVertexCount() +*/ +int QOpenGLShaderProgram::maxGeometryOutputVertices() const +{ + GLint n = 0; +// glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &n); + return n; +} + +/*! + Sets the maximum number of vertices the current geometry shader + program will produce, if active, to \a count. + + \since 4.7 + + This parameter takes effect the next time the program is linked. +*/ +void QOpenGLShaderProgram::setGeometryOutputVertexCount(int count) +{ +#ifndef QT_NO_DEBUG + int max = maxGeometryOutputVertices(); + if (count > max) { + qWarning("QOpenGLShaderProgram::setGeometryOutputVertexCount: count: %d higher than maximum: %d", + count, max); + } +#endif + d_func()->geometryVertexCount = count; +} + + +/*! + Returns the maximum number of vertices the current geometry shader + program will produce, if active. + + \since 4.7 + + This parameter takes effect the ntext time the program is linked. +*/ +int QOpenGLShaderProgram::geometryOutputVertexCount() const +{ + return d_func()->geometryVertexCount; +} + + +/*! + Sets the input type from \a inputType. + + This parameter takes effect the next time the program is linked. +*/ +void QOpenGLShaderProgram::setGeometryInputType(GLenum inputType) +{ + d_func()->geometryInputType = inputType; +} + + +/*! + Returns the geometry shader input type, if active. + + This parameter takes effect the next time the program is linked. + + \since 4.7 + */ + +GLenum QOpenGLShaderProgram::geometryInputType() const +{ + return d_func()->geometryInputType; +} + + +/*! + Sets the output type from the geometry shader, if active, to + \a outputType. + + This parameter takes effect the next time the program is linked. + + \since 4.7 +*/ +void QOpenGLShaderProgram::setGeometryOutputType(GLenum outputType) +{ + d_func()->geometryOutputType = outputType; +} + + +/*! + Returns the geometry shader output type, if active. + + This parameter takes effect the next time the program is linked. + + \since 4.7 + */ +GLenum QOpenGLShaderProgram::geometryOutputType() const +{ + return d_func()->geometryOutputType; +} + + +/*! + Returns true if shader programs written in the OpenGL Shading + Language (GLSL) are supported on this system; false otherwise. + + The \a context is used to resolve the GLSL extensions. + If \a context is null, then QOpenGLContext::currentContext() is used. +*/ +bool QOpenGLShaderProgram::hasOpenGLShaderPrograms(QOpenGLContext *context) +{ +#if !defined(QT_OPENGL_ES_2) + if (!context) + context = QOpenGLContext::currentContext(); + if (!context) + return false; + return QOpenGLFunctions(context).hasOpenGLFeature(QOpenGLFunctions::Shaders); +#else + Q_UNUSED(context); + return true; +#endif +} + +/*! + \internal +*/ +void QOpenGLShaderProgram::shaderDestroyed() +{ + Q_D(QOpenGLShaderProgram); + QOpenGLShader *shader = qobject_cast(sender()); + if (shader && !d->removingShaders) + removeShader(shader); +} + + +#undef ctx +#undef context + +/*! + Returns true if shader programs of type \a type are supported on + this system; false otherwise. + + The \a context is used to resolve the GLSL extensions. + If \a context is null, then QOpenGLContext::currentContext() is used. + + \since 4.7 +*/ +bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context) +{ + if (!context) + context = QOpenGLContext::currentContext(); + if (!context) + return false; + + if ((type & ~(Geometry | Vertex | Fragment)) || type == 0) + return false; + +#if 0 + bool resolved = qt_resolve_glsl_extensions(const_cast(context)); + if (!resolved) + return false; + + if ((type & Geometry) && !QByteArray((const char *) glGetString(GL_EXTENSIONS)).contains("GL_EXT_geometry_shader4")) + return false; +#endif + + return true; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglshaderprogram.h b/src/gui/opengl/qopenglshaderprogram.h new file mode 100644 index 0000000000..4c123749a2 --- /dev/null +++ b/src/gui/opengl/qopenglshaderprogram.h @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLSHADERPROGRAM_H +#define QOPENGLSHADERPROGRAM_H + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QOpenGLContext; +class QOpenGLShaderProgram; +class QOpenGLShaderPrivate; + +class Q_GUI_EXPORT QOpenGLShader : public QObject +{ + Q_OBJECT +public: + enum ShaderTypeBit + { + Vertex = 0x0001, + Fragment = 0x0002, + Geometry = 0x0004 + }; + Q_DECLARE_FLAGS(ShaderType, ShaderTypeBit) + + explicit QOpenGLShader(QOpenGLShader::ShaderType type, QObject *parent = 0); + virtual ~QOpenGLShader(); + + QOpenGLShader::ShaderType shaderType() const; + + bool compileSourceCode(const char *source); + bool compileSourceCode(const QByteArray& source); + bool compileSourceCode(const QString& source); + bool compileSourceFile(const QString& fileName); + + QByteArray sourceCode() const; + + bool isCompiled() const; + QString log() const; + + GLuint shaderId() const; + + static bool hasOpenGLShaders(ShaderType type, QOpenGLContext *context = 0); + +private: + friend class QOpenGLShaderProgram; + + Q_DISABLE_COPY(QOpenGLShader) + Q_DECLARE_PRIVATE(QOpenGLShader) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLShader::ShaderType) + + +class QOpenGLShaderProgramPrivate; + +#ifndef GL_EXT_geometry_shader4 +# define GL_LINES_ADJACENCY_EXT 0xA +# define GL_LINE_STRIP_ADJACENCY_EXT 0xB +# define GL_TRIANGLES_ADJACENCY_EXT 0xC +# define GL_TRIANGLE_STRIP_ADJACENCY_EXT 0xD +#endif + + +class Q_GUI_EXPORT QOpenGLShaderProgram : public QObject +{ + Q_OBJECT +public: + explicit QOpenGLShaderProgram(QObject *parent = 0); + virtual ~QOpenGLShaderProgram(); + + bool addShader(QOpenGLShader *shader); + void removeShader(QOpenGLShader *shader); + QList shaders() const; + + bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source); + bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray& source); + bool addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString& source); + bool addShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString& fileName); + + void removeAllShaders(); + + virtual bool link(); + bool isLinked() const; + QString log() const; + + bool bind(); + void release(); + + GLuint programId() const; + + int maxGeometryOutputVertices() const; + + void setGeometryOutputVertexCount(int count); + int geometryOutputVertexCount() const; + + void setGeometryInputType(GLenum inputType); + GLenum geometryInputType() const; + + void setGeometryOutputType(GLenum outputType); + GLenum geometryOutputType() const; + + void bindAttributeLocation(const char *name, int location); + void bindAttributeLocation(const QByteArray& name, int location); + void bindAttributeLocation(const QString& name, int location); + + int attributeLocation(const char *name) const; + int attributeLocation(const QByteArray& name) const; + int attributeLocation(const QString& name) const; + + void setAttributeValue(int location, GLfloat value); + void setAttributeValue(int location, GLfloat x, GLfloat y); + void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z); + void setAttributeValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setAttributeValue(int location, const QVector2D& value); + void setAttributeValue(int location, const QVector3D& value); + void setAttributeValue(int location, const QVector4D& value); + void setAttributeValue(int location, const QColor& value); + void setAttributeValue(int location, const GLfloat *values, int columns, int rows); + + void setAttributeValue(const char *name, GLfloat value); + void setAttributeValue(const char *name, GLfloat x, GLfloat y); + void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z); + void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setAttributeValue(const char *name, const QVector2D& value); + void setAttributeValue(const char *name, const QVector3D& value); + void setAttributeValue(const char *name, const QVector4D& value); + void setAttributeValue(const char *name, const QColor& value); + void setAttributeValue(const char *name, const GLfloat *values, int columns, int rows); + + void setAttributeArray + (int location, const GLfloat *values, int tupleSize, int stride = 0); + void setAttributeArray + (int location, const QVector2D *values, int stride = 0); + void setAttributeArray + (int location, const QVector3D *values, int stride = 0); + void setAttributeArray + (int location, const QVector4D *values, int stride = 0); + void setAttributeArray + (int location, GLenum type, const void *values, int tupleSize, int stride = 0); + void setAttributeArray + (const char *name, const GLfloat *values, int tupleSize, int stride = 0); + void setAttributeArray + (const char *name, const QVector2D *values, int stride = 0); + void setAttributeArray + (const char *name, const QVector3D *values, int stride = 0); + void setAttributeArray + (const char *name, const QVector4D *values, int stride = 0); + void setAttributeArray + (const char *name, GLenum type, const void *values, int tupleSize, int stride = 0); + + void setAttributeBuffer + (int location, GLenum type, int offset, int tupleSize, int stride = 0); + void setAttributeBuffer + (const char *name, GLenum type, int offset, int tupleSize, int stride = 0); + + void enableAttributeArray(int location); + void enableAttributeArray(const char *name); + void disableAttributeArray(int location); + void disableAttributeArray(const char *name); + + int uniformLocation(const char *name) const; + int uniformLocation(const QByteArray& name) const; + int uniformLocation(const QString& name) const; + + void setUniformValue(int location, GLfloat value); + void setUniformValue(int location, GLint value); + void setUniformValue(int location, GLuint value); + void setUniformValue(int location, GLfloat x, GLfloat y); + void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z); + void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setUniformValue(int location, const QVector2D& value); + void setUniformValue(int location, const QVector3D& value); + void setUniformValue(int location, const QVector4D& value); + void setUniformValue(int location, const QColor& color); + void setUniformValue(int location, const QPoint& point); + void setUniformValue(int location, const QPointF& point); + void setUniformValue(int location, const QSize& size); + void setUniformValue(int location, const QSizeF& size); + void setUniformValue(int location, const QMatrix2x2& value); + void setUniformValue(int location, const QMatrix2x3& value); + void setUniformValue(int location, const QMatrix2x4& value); + void setUniformValue(int location, const QMatrix3x2& value); + void setUniformValue(int location, const QMatrix3x3& value); + void setUniformValue(int location, const QMatrix3x4& value); + void setUniformValue(int location, const QMatrix4x2& value); + void setUniformValue(int location, const QMatrix4x3& value); + void setUniformValue(int location, const QMatrix4x4& value); + void setUniformValue(int location, const GLfloat value[2][2]); + void setUniformValue(int location, const GLfloat value[3][3]); + void setUniformValue(int location, const GLfloat value[4][4]); + void setUniformValue(int location, const QTransform& value); + + void setUniformValue(const char *name, GLfloat value); + void setUniformValue(const char *name, GLint value); + void setUniformValue(const char *name, GLuint value); + void setUniformValue(const char *name, GLfloat x, GLfloat y); + void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z); + void setUniformValue(const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w); + void setUniformValue(const char *name, const QVector2D& value); + void setUniformValue(const char *name, const QVector3D& value); + void setUniformValue(const char *name, const QVector4D& value); + void setUniformValue(const char *name, const QColor& color); + void setUniformValue(const char *name, const QPoint& point); + void setUniformValue(const char *name, const QPointF& point); + void setUniformValue(const char *name, const QSize& size); + void setUniformValue(const char *name, const QSizeF& size); + void setUniformValue(const char *name, const QMatrix2x2& value); + void setUniformValue(const char *name, const QMatrix2x3& value); + void setUniformValue(const char *name, const QMatrix2x4& value); + void setUniformValue(const char *name, const QMatrix3x2& value); + void setUniformValue(const char *name, const QMatrix3x3& value); + void setUniformValue(const char *name, const QMatrix3x4& value); + void setUniformValue(const char *name, const QMatrix4x2& value); + void setUniformValue(const char *name, const QMatrix4x3& value); + void setUniformValue(const char *name, const QMatrix4x4& value); + void setUniformValue(const char *name, const GLfloat value[2][2]); + void setUniformValue(const char *name, const GLfloat value[3][3]); + void setUniformValue(const char *name, const GLfloat value[4][4]); + void setUniformValue(const char *name, const QTransform& value); + + void setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize); + void setUniformValueArray(int location, const GLint *values, int count); + void setUniformValueArray(int location, const GLuint *values, int count); + void setUniformValueArray(int location, const QVector2D *values, int count); + void setUniformValueArray(int location, const QVector3D *values, int count); + void setUniformValueArray(int location, const QVector4D *values, int count); + void setUniformValueArray(int location, const QMatrix2x2 *values, int count); + void setUniformValueArray(int location, const QMatrix2x3 *values, int count); + void setUniformValueArray(int location, const QMatrix2x4 *values, int count); + void setUniformValueArray(int location, const QMatrix3x2 *values, int count); + void setUniformValueArray(int location, const QMatrix3x3 *values, int count); + void setUniformValueArray(int location, const QMatrix3x4 *values, int count); + void setUniformValueArray(int location, const QMatrix4x2 *values, int count); + void setUniformValueArray(int location, const QMatrix4x3 *values, int count); + void setUniformValueArray(int location, const QMatrix4x4 *values, int count); + + void setUniformValueArray(const char *name, const GLfloat *values, int count, int tupleSize); + void setUniformValueArray(const char *name, const GLint *values, int count); + void setUniformValueArray(const char *name, const GLuint *values, int count); + void setUniformValueArray(const char *name, const QVector2D *values, int count); + void setUniformValueArray(const char *name, const QVector3D *values, int count); + void setUniformValueArray(const char *name, const QVector4D *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix2x4 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix3x4 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x2 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x3 *values, int count); + void setUniformValueArray(const char *name, const QMatrix4x4 *values, int count); + + static bool hasOpenGLShaderPrograms(QOpenGLContext *context = 0); + +private Q_SLOTS: + void shaderDestroyed(); + +private: + Q_DISABLE_COPY(QOpenGLShaderProgram) + Q_DECLARE_PRIVATE(QOpenGLShaderProgram) + + bool init(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/gui/opengl/qpaintengineex_opengl2.cpp b/src/gui/opengl/qpaintengineex_opengl2.cpp new file mode 100644 index 0000000000..7bdac27336 --- /dev/null +++ b/src/gui/opengl/qpaintengineex_opengl2.cpp @@ -0,0 +1,2454 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + When the active program changes, we need to update it's uniforms. + We could track state for each program and only update stale uniforms + - Could lead to lots of overhead if there's a lot of programs + We could update all the uniforms when the program changes + - Could end up updating lots of uniforms which don't need updating + + Updating uniforms should be cheap, so the overhead of updating up-to-date + uniforms should be minimal. It's also less complex. + + Things which _may_ cause a different program to be used: + - Change in brush/pen style + - Change in painter opacity + - Change in composition mode + + Whenever we set a mode on the shader manager - it needs to tell us if it had + to switch to a different program. + + The shader manager should only switch when we tell it to. E.g. if we set a new + brush style and then switch to transparent painter, we only want it to compile + and use the correct program when we really need it. +*/ + +// #define QT_OPENGL_CACHE_AS_VBOS + +#include "qopenglgradientcache_p.h" +#include "qpaintengineex_opengl2_p.h" + +#include //for memcpy +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qopenglengineshadermanager_p.h" +#include "qopengl2pexvertexarray_p.h" +#include "qtriangulatingstroker_p.h" +#include "qtextureglyphcache_gl_p.h" + +#include + +QT_BEGIN_NAMESPACE + +#if defined(Q_WS_WIN) +extern Q_GUI_EXPORT bool qt_cleartype_enabled; +#endif + +#ifdef Q_WS_MAC +extern bool qt_applefontsmoothing_enabled; +#endif + +Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); + +////////////////////////////////// Private Methods ////////////////////////////////////////// + +QOpenGL2PaintEngineExPrivate::~QOpenGL2PaintEngineExPrivate() +{ + delete shaderManager; + + while (pathCaches.size()) { + QVectorPath::CacheEntry *e = *(pathCaches.constBegin()); + e->cleanup(e->engine, e->data); + e->data = 0; + e->engine = 0; + } + + if (elementIndicesVBOId != 0) { + funcs.glDeleteBuffers(1, &elementIndicesVBOId); + elementIndicesVBOId = 0; + } +} + +void QOpenGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id) +{ +// glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit? + if (id != GLuint(-1) && id == lastTextureUsed) + return; + + lastTextureUsed = id; + + if (smoothPixmapTransform) { + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + glTexParameterf(target, GL_TEXTURE_WRAP_S, wrapMode); + glTexParameterf(target, GL_TEXTURE_WRAP_T, wrapMode); +} + + +inline QColor qt_premultiplyColor(QColor c, GLfloat opacity) +{ + qreal alpha = c.alphaF() * opacity; + c.setAlphaF(alpha); + c.setRedF(c.redF() * alpha); + c.setGreenF(c.greenF() * alpha); + c.setBlueF(c.blueF() * alpha); + return c; +} + + +void QOpenGL2PaintEngineExPrivate::setBrush(const QBrush& brush) +{ + if (qbrush_fast_equals(currentBrush, brush)) + return; + + const Qt::BrushStyle newStyle = qbrush_style(brush); + Q_ASSERT(newStyle != Qt::NoBrush); + + currentBrush = brush; + if (!currentBrushPixmap.isNull()) + currentBrushPixmap = QPixmap(); + brushUniformsDirty = true; // All brushes have at least one uniform + + if (newStyle > Qt::SolidPattern) + brushTextureDirty = true; + + if (currentBrush.style() == Qt::TexturePattern + && qHasPixmapTexture(brush) && brush.texture().isQBitmap()) + { + shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::TextureSrcWithPattern); + } else { + shaderManager->setSrcPixelType(newStyle); + } + shaderManager->optimiseForBrushTransform(currentBrush.transform().type()); +} + + +void QOpenGL2PaintEngineExPrivate::useSimpleShader() +{ + shaderManager->useSimpleProgram(); + + if (matrixDirty) + updateMatrix(); +} + +void QOpenGL2PaintEngineExPrivate::updateBrushTexture() +{ + Q_Q(QOpenGL2PaintEngineEx); +// qDebug("QOpenGL2PaintEngineExPrivate::updateBrushTexture()"); + Qt::BrushStyle style = currentBrush.style(); + + if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) { + // Get the image data for the pattern + QImage texImage = qt_imageForBrush(style, false); + + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); + //ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, QOpenGLContext::InternalBindOption); + updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); + } + else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { + // Gradiant brush: All the gradiants use the same texture + + const QGradient* g = currentBrush.gradient(); + + // We apply global opacity in the fragment shaders, so we always pass 1.0 + // for opacity to the cache. + GLuint texId = QOpenGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0); + + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, texId); + + if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient) + updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); + else if (g->spread() == QGradient::ReflectSpread) + updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); + else + updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform); + } + else if (style == Qt::TexturePattern) { + currentBrushPixmap = currentBrush.texture(); + + int max_texture_size = ctx->d_func()->maxTextureSize(); + if (currentBrushPixmap.width() > max_texture_size || currentBrushPixmap.height() > max_texture_size) + currentBrushPixmap = currentBrushPixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); + + glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); + QOpenGLTexture *tex = 0;//ctx->d_func()->bindTexture(currentBrushPixmap, GL_TEXTURE_2D, GL_RGBA, + // QOpenGLContext::InternalBindOption | + // QOpenGLContext::CanFlipNativePixmapBindOption); + updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); + textureInvertedY = tex->invertedY(); + } + brushTextureDirty = false; +} + + +void QOpenGL2PaintEngineExPrivate::updateBrushUniforms() +{ +// qDebug("QOpenGL2PaintEngineExPrivate::updateBrushUniforms()"); + Qt::BrushStyle style = currentBrush.style(); + + if (style == Qt::NoBrush) + return; + + QTransform brushQTransform = currentBrush.transform(); + + if (style == Qt::SolidPattern) { + QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::FragmentColor), col); + } + else { + // All other brushes have a transform and thus need the translation point: + QPointF translationPoint; + + if (style <= Qt::DiagCrossPattern) { + QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); + + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col); + + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); + } + else if (style == Qt::LinearGradientPattern) { + const QLinearGradient *g = static_cast(currentBrush.gradient()); + + QPointF realStart = g->start(); + QPointF realFinal = g->finalStop(); + translationPoint = realStart; + + QPointF l = realFinal - realStart; + + QVector3D linearData( + l.x(), + l.y(), + 1.0f / (l.x() * l.x() + l.y() * l.y()) + ); + + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::LinearData), linearData); + + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); + } + else if (style == Qt::ConicalGradientPattern) { + const QConicalGradient *g = static_cast(currentBrush.gradient()); + translationPoint = g->center(); + + GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0; + + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Angle), angle); + + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); + } + else if (style == Qt::RadialGradientPattern) { + const QRadialGradient *g = static_cast(currentBrush.gradient()); + QPointF realCenter = g->center(); + QPointF realFocal = g->focalPoint(); + qreal realRadius = g->centerRadius() - g->focalRadius(); + translationPoint = realFocal; + + QPointF fmp = realCenter - realFocal; + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Fmp), fmp); + + GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius; + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Inverse2Fmp2MRadius2), + GLfloat(1.0 / (2.0*fmp2_m_radius2))); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::SqrFr), + GLfloat(g->focalRadius() * g->focalRadius())); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BRadius), + GLfloat(2 * (g->centerRadius() - g->focalRadius()) * g->focalRadius()), + g->focalRadius(), + g->centerRadius() - g->focalRadius()); + + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); + } + else if (style == Qt::TexturePattern) { + const QPixmap& texPixmap = currentBrush.texture(); + + if (qHasPixmapTexture(currentBrush) && currentBrush.texture().isQBitmap()) { + QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col); + } + + QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height()); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::InvertedTextureSize), invertedTextureSize); + + QVector2D halfViewportSize(width*0.5, height*0.5); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); + } + else + qWarning("QOpenGL2PaintEngineEx: Unimplemented fill style"); + + const QPointF &brushOrigin = q->state()->brushOrigin; + QTransform matrix = q->state()->matrix; + matrix.translate(brushOrigin.x(), brushOrigin.y()); + + QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y()); + qreal m22 = -1; + qreal dy = height; + if (device->isFlipped()) { + m22 = 1; + dy = 0; + } + QTransform gl_to_qt(1, 0, 0, m22, 0, dy); + QTransform inv_matrix; + if (style == Qt::TexturePattern && textureInvertedY == -1) + inv_matrix = gl_to_qt * (QTransform(1, 0, 0, -1, 0, currentBrush.texture().height()) * brushQTransform * matrix).inverted() * translate; + else + inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate; + + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BrushTransform), inv_matrix); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT); + } + brushUniformsDirty = false; +} + + +// This assumes the shader manager has already setup the correct shader program +void QOpenGL2PaintEngineExPrivate::updateMatrix() +{ +// qDebug("QOpenGL2PaintEngineExPrivate::updateMatrix()"); + + const QTransform& transform = q->state()->matrix; + + // The projection matrix converts from Qt's coordinate system to GL's coordinate system + // * GL's viewport is 2x2, Qt's is width x height + // * GL has +y -> -y going from bottom -> top, Qt is the other way round + // * GL has [0,0] in the center, Qt has it in the top-left + // + // This results in the Projection matrix below, which is multiplied by the painter's + // transformation matrix, as shown below: + // + // Projection Matrix Painter Transform + // ------------------------------------------------ ------------------------ + // | 2.0 / width | 0.0 | -1.0 | | m11 | m21 | dx | + // | 0.0 | -2.0 / height | 1.0 | * | m12 | m22 | dy | + // | 0.0 | 0.0 | 1.0 | | m13 | m23 | m33 | + // ------------------------------------------------ ------------------------ + // + // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies + + const GLfloat wfactor = 2.0f / width; + GLfloat hfactor = -2.0f / height; + + GLfloat dx = transform.dx(); + GLfloat dy = transform.dy(); + + if (device->isFlipped()) { + hfactor *= -1; + dy -= height; + } + + // Non-integer translates can have strange effects for some rendering operations such as + // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid. + if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) { + // 0.50 needs to rounded down to 0.0 for consistency with raster engine: + dx = ceilf(dx - 0.5f); + dy = ceilf(dy - 0.5f); + } + pmvMatrix[0][0] = (wfactor * transform.m11()) - transform.m13(); + pmvMatrix[1][0] = (wfactor * transform.m21()) - transform.m23(); + pmvMatrix[2][0] = (wfactor * dx) - transform.m33(); + pmvMatrix[0][1] = (hfactor * transform.m12()) + transform.m13(); + pmvMatrix[1][1] = (hfactor * transform.m22()) + transform.m23(); + pmvMatrix[2][1] = (hfactor * dy) + transform.m33(); + pmvMatrix[0][2] = transform.m13(); + pmvMatrix[1][2] = transform.m23(); + pmvMatrix[2][2] = transform.m33(); + + // 1/10000 == 0.0001, so we have good enough res to cover curves + // that span the entire widget... + inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), + qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), + qreal(0.0001)); + + matrixDirty = false; + matrixUniformDirty = true; + + // Set the PMV matrix attribute. As we use an attributes rather than uniforms, we only + // need to do this once for every matrix change and persists across all shader programs. + funcs.glVertexAttrib3fv(QT_PMV_MATRIX_1_ATTR, pmvMatrix[0]); + funcs.glVertexAttrib3fv(QT_PMV_MATRIX_2_ATTR, pmvMatrix[1]); + funcs.glVertexAttrib3fv(QT_PMV_MATRIX_3_ATTR, pmvMatrix[2]); + + dasher.setInvScale(inverseScale); + stroker.setInvScale(inverseScale); +} + + +void QOpenGL2PaintEngineExPrivate::updateCompositionMode() +{ + // NOTE: The entire paint engine works on pre-multiplied data - which is why some of these + // composition modes look odd. +// qDebug() << "QOpenGL2PaintEngineExPrivate::updateCompositionMode() - Setting GL composition mode for " << q->state()->composition_mode; + switch(q->state()->composition_mode) { + case QPainter::CompositionMode_SourceOver: + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + break; + case QPainter::CompositionMode_DestinationOver: + glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE); + break; + case QPainter::CompositionMode_Clear: + glBlendFunc(GL_ZERO, GL_ZERO); + break; + case QPainter::CompositionMode_Source: + glBlendFunc(GL_ONE, GL_ZERO); + break; + case QPainter::CompositionMode_Destination: + glBlendFunc(GL_ZERO, GL_ONE); + break; + case QPainter::CompositionMode_SourceIn: + glBlendFunc(GL_DST_ALPHA, GL_ZERO); + break; + case QPainter::CompositionMode_DestinationIn: + glBlendFunc(GL_ZERO, GL_SRC_ALPHA); + break; + case QPainter::CompositionMode_SourceOut: + glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO); + break; + case QPainter::CompositionMode_DestinationOut: + glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + break; + case QPainter::CompositionMode_SourceAtop: + glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case QPainter::CompositionMode_DestinationAtop: + glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA); + break; + case QPainter::CompositionMode_Xor: + glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case QPainter::CompositionMode_Plus: + glBlendFunc(GL_ONE, GL_ONE); + break; + default: + qWarning("Unsupported composition mode"); + break; + } + + compositionModeDirty = false; +} + +static inline void setCoords(GLfloat *coords, const QOpenGLRect &rect) +{ + coords[0] = rect.left; + coords[1] = rect.top; + coords[2] = rect.right; + coords[3] = rect.top; + coords[4] = rect.right; + coords[5] = rect.bottom; + coords[6] = rect.left; + coords[7] = rect.bottom; +} + +void QOpenGL2PaintEngineExPrivate::drawTexture(const QOpenGLRect& dest, const QOpenGLRect& src, const QSize &textureSize, bool opaque, bool pattern) +{ + // Setup for texture drawing + currentBrush = noBrush; + shaderManager->setSrcPixelType(pattern ? QOpenGLEngineShaderManager::PatternSrc : QOpenGLEngineShaderManager::ImageSrc); + + if (snapToPixelGrid) { + snapToPixelGrid = false; + matrixDirty = true; + } + + if (prepareForDraw(opaque)) + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); + + if (pattern) { + QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col); + } + + GLfloat dx = 1.0 / textureSize.width(); + GLfloat dy = 1.0 / textureSize.height(); + + QOpenGLRect srcTextureRect(src.left*dx, src.top*dy, src.right*dx, src.bottom*dy); + + setCoords(staticVertexCoordinateArray, dest); + setCoords(staticTextureCoordinateArray, srcTextureRect); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} + +void QOpenGL2PaintEngineEx::beginNativePainting() +{ + Q_D(QOpenGL2PaintEngineEx); + ensureActive(); + d->transferMode(BrushDrawingMode); + + d->nativePaintingActive = true; + + d->funcs.glUseProgram(0); + + // Disable all the vertex attribute arrays: + for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) + d->funcs.glDisableVertexAttribArray(i); + +#ifndef QT_OPENGL_ES_2 + const QSurfaceFormat &fmt = d->device->format(); + if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 1) + || fmt.profile() == QSurfaceFormat::CompatibilityProfile) + { + // be nice to people who mix OpenGL 1.x code with QPainter commands + // by setting modelview and projection matrices to mirror the GL 1 + // paint engine + const QTransform& mtx = state()->matrix; + + float mv_matrix[4][4] = + { + { float(mtx.m11()), float(mtx.m12()), 0, float(mtx.m13()) }, + { float(mtx.m21()), float(mtx.m22()), 0, float(mtx.m23()) }, + { 0, 0, 1, 0 }, + { float(mtx.dx()), float(mtx.dy()), 0, float(mtx.m33()) } + }; + + const QSize sz = d->device->size(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); + + glMatrixMode(GL_MODELVIEW); + glLoadMatrixf(&mv_matrix[0][0]); + } +#endif + + d->lastTextureUsed = GLuint(-1); + d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); + d->resetGLState(); + + d->shaderManager->setDirty(); + + d->needsSync = true; +} + +void QOpenGL2PaintEngineExPrivate::resetGLState() +{ + glDisable(GL_BLEND); + glActiveTexture(GL_TEXTURE0); + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDepthMask(true); + glDepthFunc(GL_LESS); + funcs.glClearDepthf(1); + glStencilMask(0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_ALWAYS, 0, 0xff); + setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false); + setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false); + setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); +#ifndef QT_OPENGL_ES_2 + // gl_Color, corresponding to vertex attribute 3, may have been changed + float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + funcs.glVertexAttrib4fv(3, color); +#endif +} + +void QOpenGL2PaintEngineEx::endNativePainting() +{ + Q_D(QOpenGL2PaintEngineEx); + d->needsSync = true; + d->nativePaintingActive = false; +} + +void QOpenGL2PaintEngineEx::invalidateState() +{ + Q_D(QOpenGL2PaintEngineEx); + d->needsSync = true; +} + +bool QOpenGL2PaintEngineEx::isNativePaintingActive() const { + Q_D(const QOpenGL2PaintEngineEx); + return d->nativePaintingActive; +} + +void QOpenGL2PaintEngineExPrivate::transferMode(EngineMode newMode) +{ + if (newMode == mode) + return; + + if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) { + lastTextureUsed = GLuint(-1); + } + + if (newMode == TextDrawingMode) { + shaderManager->setHasComplexGeometry(true); + } else { + shaderManager->setHasComplexGeometry(false); + } + + if (newMode == ImageDrawingMode) { + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray); + setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray); + } + + if (newMode == ImageArrayDrawingMode) { + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); + setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); + setVertexAttributePointer(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data()); + } + + // This needs to change when we implement high-quality anti-aliasing... + if (newMode != TextDrawingMode) + shaderManager->setMaskType(QOpenGLEngineShaderManager::NoMask); + + mode = newMode; +} + +struct QOpenGL2PEVectorPathCache +{ +#ifdef QT_OPENGL_CACHE_AS_VBOS + GLuint vbo; + GLuint ibo; +#else + float *vertices; + void *indices; +#endif + int vertexCount; + int indexCount; + GLenum primitiveType; + qreal iscale; +}; + +void QOpenGL2PaintEngineExPrivate::cleanupVectorPath(QPaintEngineEx *engine, void *data) +{ + QOpenGL2PEVectorPathCache *c = (QOpenGL2PEVectorPathCache *) data; +#ifdef QT_OPENGL_CACHE_AS_VBOS + Q_ASSERT(engine->type() == QPaintEngine::OpenGL2); + static_cast(engine)->d_func()->unusedVBOSToClean << c->vbo; + if (c->ibo) + d->unusedIBOSToClean << c->ibo; +#else + Q_UNUSED(engine); + qFree(c->vertices); + qFree(c->indices); +#endif + delete c; +} + +// Assumes everything is configured for the brush you want to use +void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) +{ + transferMode(BrushDrawingMode); + + if (snapToPixelGrid) { + snapToPixelGrid = false; + matrixDirty = true; + } + + // Might need to call updateMatrix to re-calculate inverseScale + if (matrixDirty) + updateMatrix(); + + const QPointF* const points = reinterpret_cast(path.points()); + + // Check to see if there's any hints + if (path.shape() == QVectorPath::RectangleHint) { + QOpenGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y()); + prepareForDraw(currentBrush.isOpaque()); + composite(rect); + } else if (path.isConvex()) { + + if (path.isCacheable()) { + QVectorPath::CacheEntry *data = path.lookupCacheData(q); + QOpenGL2PEVectorPathCache *cache; + + bool updateCache = false; + + if (data) { + cache = (QOpenGL2PEVectorPathCache *) data->data; + // Check if scale factor is exceeded for curved paths and generate curves if so... + if (path.isCurved()) { + qreal scaleFactor = cache->iscale / inverseScale; + if (scaleFactor < 0.5 || scaleFactor > 2.0) { +#ifdef QT_OPENGL_CACHE_AS_VBOS + glDeleteBuffers(1, &cache->vbo); + cache->vbo = 0; + Q_ASSERT(cache->ibo == 0); +#else + qFree(cache->vertices); + Q_ASSERT(cache->indices == 0); +#endif + updateCache = true; + } + } + } else { + cache = new QOpenGL2PEVectorPathCache; + data = const_cast(path).addCacheData(q, cache, cleanupVectorPath); + updateCache = true; + } + + // Flatten the path at the current scale factor and fill it into the cache struct. + if (updateCache) { + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale, false); + int vertexCount = vertexCoordinateArray.vertexCount(); + int floatSizeInBytes = vertexCount * 2 * sizeof(float); + cache->vertexCount = vertexCount; + cache->indexCount = 0; + cache->primitiveType = GL_TRIANGLE_FAN; + cache->iscale = inverseScale; +#ifdef QT_OPENGL_CACHE_AS_VBOS + glGenBuffers(1, &cache->vbo); + glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); + glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW); + cache->ibo = 0; +#else + cache->vertices = (float *) qMalloc(floatSizeInBytes); + memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes); + cache->indices = 0; +#endif + } + + prepareForDraw(currentBrush.isOpaque()); +#ifdef QT_OPENGL_CACHE_AS_VBOS + glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); +#else + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices); +#endif + glDrawArrays(cache->primitiveType, 0, cache->vertexCount); + + } else { + // printf(" - Marking path as cachable...\n"); + // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable + path.makeCacheable(); + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale, false); + prepareForDraw(currentBrush.isOpaque()); + drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); + } + + } else { + bool useCache = path.isCacheable(); + if (useCache) { + QRectF bbox = path.controlPointRect(); + // If the path doesn't fit within these limits, it is possible that the triangulation will fail. + useCache &= (bbox.left() > -0x8000 * inverseScale) + && (bbox.right() < 0x8000 * inverseScale) + && (bbox.top() > -0x8000 * inverseScale) + && (bbox.bottom() < 0x8000 * inverseScale); + } + + if (useCache) { + QVectorPath::CacheEntry *data = path.lookupCacheData(q); + QOpenGL2PEVectorPathCache *cache; + + bool updateCache = false; + + if (data) { + cache = (QOpenGL2PEVectorPathCache *) data->data; + // Check if scale factor is exceeded for curved paths and generate curves if so... + if (path.isCurved()) { + qreal scaleFactor = cache->iscale / inverseScale; + if (scaleFactor < 0.5 || scaleFactor > 2.0) { +#ifdef QT_OPENGL_CACHE_AS_VBOS + glDeleteBuffers(1, &cache->vbo); + glDeleteBuffers(1, &cache->ibo); +#else + qFree(cache->vertices); + qFree(cache->indices); +#endif + updateCache = true; + } + } + } else { + cache = new QOpenGL2PEVectorPathCache; + data = const_cast(path).addCacheData(q, cache, cleanupVectorPath); + updateCache = true; + } + + // Flatten the path at the current scale factor and fill it into the cache struct. + if (updateCache) { + QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale)); + cache->vertexCount = polys.vertices.size() / 2; + cache->indexCount = polys.indices.size(); + cache->primitiveType = GL_TRIANGLES; + cache->iscale = inverseScale; +#ifdef QT_OPENGL_CACHE_AS_VBOS + glGenBuffers(1, &cache->vbo); + glGenBuffers(1, &cache->ibo); + glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo); + + if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint)) + funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quint32) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW); + else + funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quint16) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW); + + QVarLengthArray vertices(polys.vertices.size()); + for (int i = 0; i < polys.vertices.size(); ++i) + vertices[i] = float(inverseScale * polys.vertices.at(i)); + funcs.glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW); +#else + cache->vertices = (float *) qMalloc(sizeof(float) * polys.vertices.size()); + if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint)) { + cache->indices = (quint32 *) qMalloc(sizeof(quint32) * polys.indices.size()); + memcpy(cache->indices, polys.indices.data(), sizeof(quint32) * polys.indices.size()); + } else { + cache->indices = (quint16 *) qMalloc(sizeof(quint16) * polys.indices.size()); + memcpy(cache->indices, polys.indices.data(), sizeof(quint16) * polys.indices.size()); + } + for (int i = 0; i < polys.vertices.size(); ++i) + cache->vertices[i] = float(inverseScale * polys.vertices.at(i)); +#endif + } + + prepareForDraw(currentBrush.isOpaque()); +#ifdef QT_OPENGL_CACHE_AS_VBOS + glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo); + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); + if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint)) + glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0); + else + glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +#else + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, cache->vertices); + if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint)) + glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, (qint32 *)cache->indices); + else + glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, (qint16 *)cache->indices); +#endif + + } else { + // printf(" - Marking path as cachable...\n"); + // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable + path.makeCacheable(); + + if (!device->format().stencilBufferSize()) { + // If there is no stencil buffer, triangulate the path instead. + + QRectF bbox = path.controlPointRect(); + // If the path doesn't fit within these limits, it is possible that the triangulation will fail. + bool withinLimits = (bbox.left() > -0x8000 * inverseScale) + && (bbox.right() < 0x8000 * inverseScale) + && (bbox.top() > -0x8000 * inverseScale) + && (bbox.bottom() < 0x8000 * inverseScale); + if (withinLimits) { + QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale)); + + QVarLengthArray vertices(polys.vertices.size()); + for (int i = 0; i < polys.vertices.size(); ++i) + vertices[i] = float(inverseScale * polys.vertices.at(i)); + + prepareForDraw(currentBrush.isOpaque()); + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, vertices.constData()); + if (funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint)) + glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_INT, polys.indices.data()); + else + glDrawElements(GL_TRIANGLES, polys.indices.size(), GL_UNSIGNED_SHORT, polys.indices.data()); + } else { + // We can't handle big, concave painter paths with OpenGL without stencil buffer. + qWarning("Painter path exceeds +/-32767 pixels."); + } + return; + } + + // The path is too complicated & needs the stencil technique + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale, false); + + fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); + + glStencilMask(0xff); + glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); + + if (q->state()->clipTestEnabled) { + // Pass when high bit is set, replace stencil value with current clip + glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT); + } else if (path.hasWindingFill()) { + // Pass when any bit is set, replace stencil value with 0 + glStencilFunc(GL_NOTEQUAL, 0, 0xff); + } else { + // Pass when high bit is set, replace stencil value with 0 + glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); + } + prepareForDraw(currentBrush.isOpaque()); + + // Stencil the brush onto the dest buffer + composite(vertexCoordinateArray.boundingRect()); + glStencilMask(0); + updateClipScissorTest(); + } + } +} + + +void QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, + int count, + int *stops, + int stopCount, + const QOpenGLRect &bounds, + StencilFillMode mode) +{ + Q_ASSERT(count || stops); + +// qDebug("QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); + glStencilMask(0xff); // Enable stencil writes + + if (dirtyStencilRegion.intersects(currentScissorBounds)) { + QVector clearRegion = dirtyStencilRegion.intersected(currentScissorBounds).rects(); + glClearStencil(0); // Clear to zero + for (int i = 0; i < clearRegion.size(); ++i) { +#ifndef QT_GL_NO_SCISSOR_TEST + setScissor(clearRegion.at(i)); +#endif + glClear(GL_STENCIL_BUFFER_BIT); + } + + dirtyStencilRegion -= currentScissorBounds; + +#ifndef QT_GL_NO_SCISSOR_TEST + updateClipScissorTest(); +#endif + } + + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes + useSimpleShader(); + glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d + + if (mode == WindingFillMode) { + Q_ASSERT(stops && !count); + if (q->state()->clipTestEnabled) { + // Flatten clip values higher than current clip, and set high bit to match current clip + glStencilFunc(GL_LEQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); + glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); + composite(bounds); + + glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT); + } else if (!stencilClean) { + // Clear stencil buffer within bounding rect + glStencilFunc(GL_ALWAYS, 0, 0xff); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + composite(bounds); + } + + // Inc. for front-facing triangle + funcs.glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP); + // Dec. for back-facing "holes" + funcs.glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP); + glStencilMask(~GL_STENCIL_HIGH_BIT); + drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); + + if (q->state()->clipTestEnabled) { + // Clear high bit of stencil outside of path + glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); + glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); + glStencilMask(GL_STENCIL_HIGH_BIT); + composite(bounds); + } + } else if (mode == OddEvenFillMode) { + glStencilMask(GL_STENCIL_HIGH_BIT); + glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit + drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); + + } else { // TriStripStrokeFillMode + Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops + glStencilMask(GL_STENCIL_HIGH_BIT); +#if 0 + glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data); + glDrawArrays(GL_TRIANGLE_STRIP, 0, count); +#else + + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + if (q->state()->clipTestEnabled) { + glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT, + ~GL_STENCIL_HIGH_BIT); + } else { + glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff); + } + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data); + glDrawArrays(GL_TRIANGLE_STRIP, 0, count); +#endif + } + + // Enable color writes & disable stencil writes + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); +} + +/* + If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1, + restore the stencil buffer to a pristine state. The current clip region + is set to 1, and the rest to 0. +*/ +void QOpenGL2PaintEngineExPrivate::resetClipIfNeeded() +{ + if (maxClip != (GL_STENCIL_HIGH_BIT - 1)) + return; + + Q_Q(QOpenGL2PaintEngineEx); + + useSimpleShader(); + glEnable(GL_STENCIL_TEST); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + QRectF bounds = q->state()->matrix.inverted().mapRect(QRectF(0, 0, width, height)); + QOpenGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); + + // Set high bit on clip region + glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xff); + glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); + glStencilMask(GL_STENCIL_HIGH_BIT); + composite(rect); + + // Reset clipping to 1 and everything else to zero + glStencilFunc(GL_NOTEQUAL, 0x01, GL_STENCIL_HIGH_BIT); + glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE); + glStencilMask(0xff); + composite(rect); + + q->state()->currentClip = 1; + q->state()->canRestoreClip = false; + + maxClip = 1; + + glStencilMask(0x0); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); +} + +bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) +{ + if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode) + updateBrushTexture(); + + if (compositionModeDirty) + updateCompositionMode(); + + if (matrixDirty) + updateMatrix(); + + const bool stateHasOpacity = q->state()->opacity < 0.99f; + if (q->state()->composition_mode == QPainter::CompositionMode_Source + || (q->state()->composition_mode == QPainter::CompositionMode_SourceOver + && srcPixelsAreOpaque && !stateHasOpacity)) + { + glDisable(GL_BLEND); + } else { + glEnable(GL_BLEND); + } + + QOpenGLEngineShaderManager::OpacityMode opacityMode; + if (mode == ImageArrayDrawingMode) { + opacityMode = QOpenGLEngineShaderManager::AttributeOpacity; + } else { + opacityMode = stateHasOpacity ? QOpenGLEngineShaderManager::UniformOpacity + : QOpenGLEngineShaderManager::NoOpacity; + if (stateHasOpacity && (mode != ImageDrawingMode)) { + // Using a brush + bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) && + (currentBrush.style() <= Qt::DiagCrossPattern); + + if ((currentBrush.style() == Qt::SolidPattern) || brushIsPattern) + opacityMode = QOpenGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader + } + } + shaderManager->setOpacityMode(opacityMode); + + bool changed = shaderManager->useCorrectShaderProg(); + // If the shader program needs changing, we change it and mark all uniforms as dirty + if (changed) { + // The shader program has changed so mark all uniforms as dirty: + brushUniformsDirty = true; + opacityUniformDirty = true; + matrixUniformDirty = true; + } + + if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode) + updateBrushUniforms(); + + if (opacityMode == QOpenGLEngineShaderManager::UniformOpacity && opacityUniformDirty) { + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity); + opacityUniformDirty = false; + } + + if (matrixUniformDirty && shaderManager->hasComplexGeometry()) { + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Matrix), + pmvMatrix); + matrixUniformDirty = false; + } + + return changed; +} + +void QOpenGL2PaintEngineExPrivate::composite(const QOpenGLRect& boundingRect) +{ + setCoords(staticVertexCoordinateArray, boundingRect); + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} + +// Draws the vertex array as a set of triangle fans. +void QOpenGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount, + GLenum primitive) +{ + // Now setup the pointer to the vertex array: + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)data); + + int previousStop = 0; + for (int i=0; i %d:", previousStop, stop-1); + for (int i=previousStop; isetBrush(brush); + d->fill(path); +} + +Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp + + +void QOpenGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) +{ + Q_D(QOpenGL2PaintEngineEx); + + const QBrush &penBrush = qpen_brush(pen); + if (qpen_style(pen) == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) + return; + + QOpenGL2PaintEngineState *s = state(); + if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) { + // QTriangulatingStroker class is not meant to support cosmetically sheared strokes. + QPaintEngineEx::stroke(path, pen); + return; + } + + ensureActive(); + d->setBrush(penBrush); + d->stroke(path, pen); +} + +void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen) +{ + const QOpenGL2PaintEngineState *s = q->state(); + if (snapToPixelGrid) { + snapToPixelGrid = false; + matrixDirty = true; + } + + const Qt::PenStyle penStyle = qpen_style(pen); + const QBrush &penBrush = qpen_brush(pen); + const bool opaque = penBrush.isOpaque() && s->opacity > 0.99; + + transferMode(BrushDrawingMode); + + // updateMatrix() is responsible for setting the inverse scale on + // the strokers, so we need to call it here and not wait for + // prepareForDraw() down below. + updateMatrix(); + + QRectF clip = q->state()->matrix.inverted().mapRect(q->state()->clipEnabled + ? q->state()->rectangleClip + : QRectF(0, 0, width, height)); + + if (penStyle == Qt::SolidLine) { + stroker.process(path, pen, clip); + + } else { // Some sort of dash + dasher.process(path, pen, clip); + + QVectorPath dashStroke(dasher.points(), + dasher.elementCount(), + dasher.elementTypes()); + stroker.process(dashStroke, pen, clip); + } + + if (!stroker.vertexCount()) + return; + + if (opaque) { + prepareForDraw(opaque); + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices()); + glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2); + +// QBrush b(Qt::green); +// d->setBrush(&b); +// d->prepareForDraw(true); +// glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2); + + } else { + qreal width = qpen_widthf(pen) / 2; + if (width == 0) + width = 0.5; + qreal extra = pen.joinStyle() == Qt::MiterJoin + ? qMax(pen.miterLimit() * width, width) + : width; + + if (pen.isCosmetic()) + extra = extra * inverseScale; + + QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); + + fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2, + 0, 0, bounds, QOpenGL2PaintEngineExPrivate::TriStripStrokeFillMode); + + glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); + + // Pass when any bit is set, replace stencil value with 0 + glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); + prepareForDraw(false); + + // Stencil the brush onto the dest buffer + composite(bounds); + + glStencilMask(0); + + updateClipScissorTest(); + } +} + +void QOpenGL2PaintEngineEx::penChanged() { } +void QOpenGL2PaintEngineEx::brushChanged() { } +void QOpenGL2PaintEngineEx::brushOriginChanged() { } + +void QOpenGL2PaintEngineEx::opacityChanged() +{ +// qDebug("QOpenGL2PaintEngineEx::opacityChanged()"); + Q_D(QOpenGL2PaintEngineEx); + state()->opacityChanged = true; + + Q_ASSERT(d->shaderManager); + d->brushUniformsDirty = true; + d->opacityUniformDirty = true; +} + +void QOpenGL2PaintEngineEx::compositionModeChanged() +{ +// qDebug("QOpenGL2PaintEngineEx::compositionModeChanged()"); + Q_D(QOpenGL2PaintEngineEx); + state()->compositionModeChanged = true; + d->compositionModeDirty = true; +} + +void QOpenGL2PaintEngineEx::renderHintsChanged() +{ + state()->renderHintsChanged = true; + +#if !defined(QT_OPENGL_ES_2) + if ((state()->renderHints & QPainter::Antialiasing) + || (state()->renderHints & QPainter::HighQualityAntialiasing)) + glEnable(GL_MULTISAMPLE); + else + glDisable(GL_MULTISAMPLE); +#endif + + Q_D(QOpenGL2PaintEngineEx); + d->lastTextureUsed = GLuint(-1); + d->brushTextureDirty = true; +// qDebug("QOpenGL2PaintEngineEx::renderHintsChanged() not implemented!"); +} + +void QOpenGL2PaintEngineEx::transformChanged() +{ + Q_D(QOpenGL2PaintEngineEx); + d->matrixDirty = true; + state()->matrixChanged = true; +} + + +static const QRectF scaleRect(const QRectF &r, qreal sx, qreal sy) +{ + return QRectF(r.x() * sx, r.y() * sy, r.width() * sx, r.height() * sy); +} + +void QOpenGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, const QRectF & src) +{ + Q_D(QOpenGL2PaintEngineEx); + QOpenGLContext *ctx = d->ctx; + + int max_texture_size = ctx->d_func()->maxTextureSize(); + if (pixmap.width() > max_texture_size || pixmap.height() > max_texture_size) { + QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); + + const qreal sx = scaled.width() / qreal(pixmap.width()); + const qreal sy = scaled.height() / qreal(pixmap.height()); + + drawPixmap(dest, scaled, scaleRect(src, sx, sy)); + return; + } + + ensureActive(); + d->transferMode(ImageDrawingMode); + + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + QOpenGLTexture *texture = 0; +// ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, bindOptions); + + GLfloat top = texture->invertedY() ? (pixmap.height() - src.top()) : src.top(); + GLfloat bottom = texture->invertedY() ? (pixmap.height() - src.bottom()) : src.bottom(); + QOpenGLRect srcRect(src.left(), top, src.right(), bottom); + + bool isBitmap = pixmap.isQBitmap(); + bool isOpaque = !isBitmap && !pixmap.hasAlpha(); + + d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, + state()->renderHints & QPainter::SmoothPixmapTransform, texture->id()); + d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap); +} + +void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src, + Qt::ImageConversionFlags) +{ + Q_D(QOpenGL2PaintEngineEx); + QOpenGLContext *ctx = d->ctx; + + int max_texture_size = ctx->d_func()->maxTextureSize(); + if (image.width() > max_texture_size || image.height() > max_texture_size) { + QImage scaled = image.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); + + const qreal sx = scaled.width() / qreal(image.width()); + const qreal sy = scaled.height() / qreal(image.height()); + + drawImage(dest, scaled, scaleRect(src, sx, sy)); + return; + } + + ensureActive(); + d->transferMode(ImageDrawingMode); + + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + + QOpenGLTexture *texture = 0;//ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, bindOptions); + GLuint id = texture->id(); + + d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, + state()->renderHints & QPainter::SmoothPixmapTransform, id); + d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); +} + +void QOpenGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) +{ + Q_D(QOpenGL2PaintEngineEx); + + ensureActive(); + + QPainterState *s = state(); + float det = s->matrix.determinant(); + + // don't try to cache huge fonts or vastly transformed fonts + QFontEngine *fontEngine = textItem->fontEngine(); + const qreal pixelSize = fontEngine->fontDef.pixelSize; + if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) { + QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 + ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat) + : d->glyphCacheType; + if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { + if (d->device->alphaRequested() || s->matrix.type() > QTransform::TxTranslate + || (s->composition_mode != QPainter::CompositionMode_Source + && s->composition_mode != QPainter::CompositionMode_SourceOver)) + { + glyphType = QFontEngineGlyphCache::Raster_A8; + } + } + + d->drawCachedGlyphs(glyphType, textItem); + } else { + QPaintEngineEx::drawStaticTextItem(textItem); + } +} + +bool QOpenGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) +{ + Q_D(QOpenGL2PaintEngineEx); + if (!d->shaderManager) + return false; + + ensureActive(); + d->transferMode(ImageDrawingMode); + + d->funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, textureId); + + QOpenGLRect srcRect(src.left(), src.bottom(), src.right(), src.top()); + + d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, + state()->renderHints & QPainter::SmoothPixmapTransform, textureId); + d->drawTexture(dest, srcRect, size, false); + return true; +} + +void QOpenGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem) +{ + Q_D(QOpenGL2PaintEngineEx); + + ensureActive(); + QOpenGL2PaintEngineState *s = state(); + + const QTextItemInt &ti = static_cast(textItem); + + QTransform::TransformationType txtype = s->matrix.type(); + + float det = s->matrix.determinant(); + bool drawCached = txtype < QTransform::TxProject; + + // don't try to cache huge fonts or vastly transformed fonts + const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; + if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) + drawCached = false; + + QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 + ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) + : d->glyphCacheType; + + + if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { + if (d->device->alphaRequested() || txtype > QTransform::TxTranslate + || (state()->composition_mode != QPainter::CompositionMode_Source + && state()->composition_mode != QPainter::CompositionMode_SourceOver)) + { + glyphType = QFontEngineGlyphCache::Raster_A8; + } + } + + if (drawCached) { + QVarLengthArray positions; + QVarLengthArray glyphs; + QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); + ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); + + { + QStaticTextItem staticTextItem; + staticTextItem.chars = const_cast(ti.chars); + staticTextItem.setFontEngine(ti.fontEngine); + staticTextItem.glyphs = glyphs.data(); + staticTextItem.numChars = ti.num_chars; + staticTextItem.numGlyphs = glyphs.size(); + staticTextItem.glyphPositions = positions.data(); + + d->drawCachedGlyphs(glyphType, &staticTextItem); + } + return; + } + + QPaintEngineEx::drawTextItem(p, ti); +} + +namespace { + + class QOpenGLStaticTextUserData: public QStaticTextUserData + { + public: + QOpenGLStaticTextUserData() + : QStaticTextUserData(OpenGLUserData), cacheSize(0, 0), cacheSerialNumber(0) + { + } + + ~QOpenGLStaticTextUserData() + { + } + + QSize cacheSize; + QOpenGL2PEXVertexArray vertexCoordinateArray; + QOpenGL2PEXVertexArray textureCoordinateArray; + QFontEngineGlyphCache::Type glyphType; + int cacheSerialNumber; + }; + +} + +#if defined(Q_WS_WIN) +static bool fontSmoothingApproximately(qreal target) +{ + extern Q_GUI_EXPORT qreal qt_fontsmoothing_gamma; // qapplication_win.cpp + return (qAbs(qt_fontsmoothing_gamma - target) < 0.2); +} +#endif + +// #define QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO + +void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, + QStaticTextItem *staticTextItem) +{ + Q_Q(QOpenGL2PaintEngineEx); + + QOpenGL2PaintEngineState *s = q->state(); + + void *cacheKey = ctx->shareGroup(); + bool recreateVertexArrays = false; + + QOpenGLTextureGlyphCache *cache = + (QOpenGLTextureGlyphCache *) staticTextItem->fontEngine()->glyphCache(cacheKey, glyphType, QTransform()); + if (!cache || cache->cacheType() != glyphType || cache->contextGroup() == 0) { + cache = new QOpenGLTextureGlyphCache(glyphType, QTransform()); + staticTextItem->fontEngine()->setGlyphCache(cacheKey, cache); + recreateVertexArrays = true; + } + + if (staticTextItem->userDataNeedsUpdate) { + recreateVertexArrays = true; + } else if (staticTextItem->userData() == 0) { + recreateVertexArrays = true; + } else if (staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) { + recreateVertexArrays = true; + } else { + QOpenGLStaticTextUserData *userData = static_cast(staticTextItem->userData()); + if (userData->glyphType != glyphType) { + recreateVertexArrays = true; + } else if (userData->cacheSerialNumber != cache->serialNumber()) { + recreateVertexArrays = true; + } + } + + // We only need to update the cache with new glyphs if we are actually going to recreate the vertex arrays. + // If the cache size has changed, we do need to regenerate the vertices, but we don't need to repopulate the + // cache so this text is performed before we test if the cache size has changed. + if (recreateVertexArrays) { + cache->setPaintEnginePrivate(this); + if (!cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs, + staticTextItem->glyphs, staticTextItem->glyphPositions)) { + // No space for glyphs in cache. We need to reset it and try again. + cache->clear(); + cache->populate(staticTextItem->fontEngine(), staticTextItem->numGlyphs, + staticTextItem->glyphs, staticTextItem->glyphPositions); + } + cache->fillInPendingGlyphs(); + } + + if (cache->width() == 0 || cache->height() == 0) + return; + + transferMode(TextDrawingMode); + + int margin = cache->glyphMargin(); + + GLfloat dx = 1.0 / cache->width(); + GLfloat dy = 1.0 / cache->height(); + + // Use global arrays by default + QOpenGL2PEXVertexArray *vertexCoordinates = &vertexCoordinateArray; + QOpenGL2PEXVertexArray *textureCoordinates = &textureCoordinateArray; + + if (staticTextItem->useBackendOptimizations) { + QOpenGLStaticTextUserData *userData = 0; + + if (staticTextItem->userData() == 0 + || staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) { + + userData = new QOpenGLStaticTextUserData(); + staticTextItem->setUserData(userData); + + } else { + userData = static_cast(staticTextItem->userData()); + } + + userData->glyphType = glyphType; + userData->cacheSerialNumber = cache->serialNumber(); + + // Use cache if backend optimizations is turned on + vertexCoordinates = &userData->vertexCoordinateArray; + textureCoordinates = &userData->textureCoordinateArray; + + QSize size(cache->width(), cache->height()); + if (userData->cacheSize != size) { + recreateVertexArrays = true; + userData->cacheSize = size; + } + } + + if (recreateVertexArrays) { + vertexCoordinates->clear(); + textureCoordinates->clear(); + + bool supportsSubPixelPositions = staticTextItem->fontEngine()->supportsSubPixelPositions(); + for (int i=0; inumGlyphs; ++i) { + QFixed subPixelPosition; + if (supportsSubPixelPositions) + subPixelPosition = cache->subPixelPositionForX(staticTextItem->glyphPositions[i].x); + + QTextureGlyphCache::GlyphAndSubPixelPosition glyph(staticTextItem->glyphs[i], subPixelPosition); + + const QTextureGlyphCache::Coord &c = cache->coords[glyph]; + if (c.isNull()) + continue; + + int x = qFloor(staticTextItem->glyphPositions[i].x) + c.baseLineX - margin; + int y = qFloor(staticTextItem->glyphPositions[i].y) - c.baseLineY - margin; + + vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h)); + textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); + } + + staticTextItem->userDataNeedsUpdate = false; + } + + int numGlyphs = vertexCoordinates->vertexCount() / 4; + if (numGlyphs == 0) + return; + + if (elementIndices.size() < numGlyphs*6) { + Q_ASSERT(elementIndices.size() % 6 == 0); + int j = elementIndices.size() / 6 * 4; + while (j < numGlyphs*4) { + elementIndices.append(j + 0); + elementIndices.append(j + 0); + elementIndices.append(j + 1); + elementIndices.append(j + 2); + elementIndices.append(j + 3); + elementIndices.append(j + 3); + + j += 4; + } + +#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) + if (elementIndicesVBOId == 0) + glGenBuffers(1, &elementIndicesVBOId); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementIndices.size() * sizeof(GLushort), + elementIndices.constData(), GL_STATIC_DRAW); +#endif + } else { +#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId); +#endif + } + + setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data()); + setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data()); + + if (!snapToPixelGrid) { + snapToPixelGrid = true; + matrixDirty = true; + } + + QBrush pensBrush = q->state()->pen.brush(); + setBrush(pensBrush); + + if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { + + // Subpixel antialiasing without gamma correction + + QPainter::CompositionMode compMode = q->state()->composition_mode; + Q_ASSERT(compMode == QPainter::CompositionMode_Source + || compMode == QPainter::CompositionMode_SourceOver); + + shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass1); + + if (pensBrush.style() == Qt::SolidPattern) { + // Solid patterns can get away with only one pass. + QColor c = pensBrush.color(); + qreal oldOpacity = q->state()->opacity; + if (compMode == QPainter::CompositionMode_Source) { + c = qt_premultiplyColor(c, q->state()->opacity); + q->state()->opacity = 1; + opacityUniformDirty = true; + } + + compositionModeDirty = false; // I can handle this myself, thank you very much + prepareForDraw(false); // Text always causes src pixels to be transparent + + // prepareForDraw() have set the opacity on the current shader, so the opacity state can now be reset. + if (compMode == QPainter::CompositionMode_Source) { + q->state()->opacity = oldOpacity; + opacityUniformDirty = true; + } + + glEnable(GL_BLEND); + glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR); + glBlendColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()); + } else { + // Other brush styles need two passes. + + qreal oldOpacity = q->state()->opacity; + if (compMode == QPainter::CompositionMode_Source) { + q->state()->opacity = 1; + opacityUniformDirty = true; + pensBrush = Qt::white; + setBrush(pensBrush); + } + + compositionModeDirty = false; // I can handle this myself, thank you very much + prepareForDraw(false); // Text always causes src pixels to be transparent + glEnable(GL_BLEND); + glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + + glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, cache->texture()); + updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); + +#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) + glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); +#else + glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); +#endif + + shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass2); + + if (compMode == QPainter::CompositionMode_Source) { + q->state()->opacity = oldOpacity; + opacityUniformDirty = true; + pensBrush = q->state()->pen.brush(); + setBrush(pensBrush); + } + + compositionModeDirty = false; + prepareForDraw(false); // Text always causes src pixels to be transparent + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + } + compositionModeDirty = true; + } else { + // Greyscale/mono glyphs + + shaderManager->setMaskType(QOpenGLEngineShaderManager::PixelMask); + prepareForDraw(false); // Text always causes src pixels to be transparent + } + + QOpenGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate)?QOpenGLTextureGlyphCache::Linear:QOpenGLTextureGlyphCache::Nearest; + if (lastMaskTextureUsed != cache->texture() || cache->filterMode() != filterMode) { + + glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT); + if (lastMaskTextureUsed != cache->texture()) { + glBindTexture(GL_TEXTURE_2D, cache->texture()); + lastMaskTextureUsed = cache->texture(); + } + + if (cache->filterMode() != filterMode) { + if (filterMode == QOpenGLTextureGlyphCache::Linear) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + cache->setFilterMode(filterMode); + } + } + + bool srgbFrameBufferEnabled = false; + if (funcs.hasOpenGLExtension(QOpenGLExtensions::SRGBFrameBuffer)) { +#if defined(Q_WS_MAC) + if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) +#elif defined(Q_WS_WIN) + if (glyphType != QFontEngineGlyphCache::Raster_RGBMask || fontSmoothingApproximately(2.1)) +#else + if (false) +#endif + { + glEnable(GL_FRAMEBUFFER_SRGB); + srgbFrameBufferEnabled = true; + } + } + +#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) + glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +#else + glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, elementIndices.data()); +#endif + + if (srgbFrameBufferEnabled) + glDisable(GL_FRAMEBUFFER_SRGB); + +} + +void QOpenGL2PaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, + QPainter::PixmapFragmentHints hints) +{ + Q_D(QOpenGL2PaintEngineEx); + // Use fallback for extended composition modes. + if (state()->composition_mode > QPainter::CompositionMode_Plus) { + QPaintEngineEx::drawPixmapFragments(fragments, fragmentCount, pixmap, hints); + return; + } + + ensureActive(); + int max_texture_size = d->ctx->d_func()->maxTextureSize(); + if (pixmap.width() > max_texture_size || pixmap.height() > max_texture_size) { + QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); + d->drawPixmapFragments(fragments, fragmentCount, scaled, hints); + } else { + d->drawPixmapFragments(fragments, fragmentCount, pixmap, hints); + } +} + + +void QOpenGL2PaintEngineExPrivate::drawPixmapFragments(const QPainter::PixmapFragment *fragments, + int fragmentCount, const QPixmap &pixmap, + QPainter::PixmapFragmentHints hints) +{ + GLfloat dx = 1.0f / pixmap.size().width(); + GLfloat dy = 1.0f / pixmap.size().height(); + + vertexCoordinateArray.clear(); + textureCoordinateArray.clear(); + opacityArray.reset(); + + if (snapToPixelGrid) { + snapToPixelGrid = false; + matrixDirty = true; + } + + bool allOpaque = true; + + for (int i = 0; i < fragmentCount; ++i) { + qreal s = 0; + qreal c = 1; + if (fragments[i].rotation != 0) { + s = qFastSin(fragments[i].rotation * Q_PI / 180); + c = qFastCos(fragments[i].rotation * Q_PI / 180); + } + + qreal right = 0.5 * fragments[i].scaleX * fragments[i].width; + qreal bottom = 0.5 * fragments[i].scaleY * fragments[i].height; + QOpenGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c); + QOpenGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c); + + vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y); + vertexCoordinateArray.addVertex(-bottomLeft.x + fragments[i].x, -bottomLeft.y + fragments[i].y); + vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y); + vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y); + vertexCoordinateArray.addVertex(bottomLeft.x + fragments[i].x, bottomLeft.y + fragments[i].y); + vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y); + + QOpenGLRect src(fragments[i].sourceLeft * dx, fragments[i].sourceTop * dy, + (fragments[i].sourceLeft + fragments[i].width) * dx, + (fragments[i].sourceTop + fragments[i].height) * dy); + + textureCoordinateArray.addVertex(src.right, src.bottom); + textureCoordinateArray.addVertex(src.right, src.top); + textureCoordinateArray.addVertex(src.left, src.top); + textureCoordinateArray.addVertex(src.left, src.top); + textureCoordinateArray.addVertex(src.left, src.bottom); + textureCoordinateArray.addVertex(src.right, src.bottom); + + qreal opacity = fragments[i].opacity * q->state()->opacity; + opacityArray << opacity << opacity << opacity << opacity << opacity << opacity; + allOpaque &= (opacity >= 0.99f); + } + + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + QOpenGLTexture *texture = 0;//ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, + // QOpenGLContext::InternalBindOption + // | QOpenGLContext::CanFlipNativePixmapBindOption); + + if (texture->invertedY()) { + // Flip texture y-coordinate. + QOpenGLPoint *data = textureCoordinateArray.data(); + for (int i = 0; i < 6 * fragmentCount; ++i) + data[i].y = 1 - data[i].y; + } + + transferMode(ImageArrayDrawingMode); + + bool isBitmap = pixmap.isQBitmap(); + bool isOpaque = !isBitmap && (!pixmap.hasAlpha() || (hints & QPainter::OpaqueHint)) && allOpaque; + + updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, + q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id()); + + // Setup for texture drawing + currentBrush = noBrush; + shaderManager->setSrcPixelType(isBitmap ? QOpenGLEngineShaderManager::PatternSrc + : QOpenGLEngineShaderManager::ImageSrc); + if (prepareForDraw(isOpaque)) + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); + + if (isBitmap) { + QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); + shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col); + } + + glDrawArrays(GL_TRIANGLES, 0, 6 * fragmentCount); +} + +bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev) +{ + Q_D(QOpenGL2PaintEngineEx); + +// qDebug("QOpenGL2PaintEngineEx::begin()"); + if (pdev->devType() == QInternal::OpenGL) + d->device = static_cast(pdev); + else + d->device = QOpenGLPaintDevice::getDevice(pdev); + + if (!d->device) + return false; + + if (d->device->group() != QOpenGLContextGroup::currentContextGroup()) { + qWarning("QPainter::begin(): OpenGL resource not valid in current context"); + return false; + } + + d->ctx = QOpenGLContext::currentContext(); + d->ctx->d_func()->active_engine = this; + + d->funcs.initializeGLFunctions(); + + for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) + d->vertexAttributeArraysEnabledState[i] = false; + + const QSize sz = d->device->size(); + d->width = sz.width(); + d->height = sz.height(); + d->mode = BrushDrawingMode; + d->brushTextureDirty = true; + d->brushUniformsDirty = true; + d->matrixUniformDirty = true; + d->matrixDirty = true; + d->compositionModeDirty = true; + d->opacityUniformDirty = true; + d->needsSync = true; + d->useSystemClip = !systemClip().isEmpty(); + d->currentBrush = QBrush(); + + d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); + d->stencilClean = true; + + // Calling begin paint should make the correct context current. So, any + // code which calls into GL or otherwise needs a current context *must* + // go after beginPaint: + d->device->beginPaint(); + d->shaderManager = new QOpenGLEngineShaderManager(d->ctx); + + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + +#if !defined(QT_OPENGL_ES_2) + glDisable(GL_MULTISAMPLE); +#endif + + d->glyphCacheType = QFontEngineGlyphCache::Raster_A8; + +#if !defined(QT_OPENGL_ES_2) +#if defined(Q_WS_WIN) + if (qt_cleartype_enabled + && (fontSmoothingApproximately(1.0) || fontSmoothingApproximately(2.1))) +#endif +#if defined(Q_WS_MAC) + if (qt_applefontsmoothing_enabled) +#endif + d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask; +#endif + +#if defined(QT_OPENGL_ES_2) + // OpenGL ES can't switch MSAA off, so if the gl paint device is + // multisampled, it's always multisampled. + d->multisamplingAlwaysEnabled = d->device->format().samples() > 1; +#else + d->multisamplingAlwaysEnabled = false; +#endif + + return true; +} + +bool QOpenGL2PaintEngineEx::end() +{ + Q_D(QOpenGL2PaintEngineEx); + + QOpenGLContext *ctx = d->ctx; + d->funcs.glUseProgram(0); + d->transferMode(BrushDrawingMode); + d->device->endPaint(); + + ctx->d_func()->active_engine = 0; + + d->resetGLState(); + + delete d->shaderManager; + d->shaderManager = 0; + d->currentBrush = QBrush(); + +#ifdef QT_OPENGL_CACHE_AS_VBOS + if (!d->unusedVBOSToClean.isEmpty()) { + glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData()); + d->unusedVBOSToClean.clear(); + } + if (!d->unusedIBOSToClean.isEmpty()) { + glDeleteBuffers(d->unusedIBOSToClean.size(), d->unusedIBOSToClean.constData()); + d->unusedIBOSToClean.clear(); + } +#endif + + return false; +} + +void QOpenGL2PaintEngineEx::ensureActive() +{ + Q_D(QOpenGL2PaintEngineEx); + QOpenGLContext *ctx = d->ctx; + + if (isActive() && ctx->d_func()->active_engine != this) { + ctx->d_func()->active_engine = this; + d->needsSync = true; + } + + d->device->ensureActiveTarget(); + + if (d->needsSync) { + d->transferMode(BrushDrawingMode); + glViewport(0, 0, d->width, d->height); + d->needsSync = false; + d->lastMaskTextureUsed = 0; + d->shaderManager->setDirty(); + d->syncGlState(); + for (int i = 0; i < 3; ++i) + d->vertexAttribPointers[i] = (GLfloat*)-1; // Assume the pointers are clobbered + setState(state()); + } +} + +void QOpenGL2PaintEngineExPrivate::updateClipScissorTest() +{ + Q_Q(QOpenGL2PaintEngineEx); + if (q->state()->clipTestEnabled) { + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); + } else { + glDisable(GL_STENCIL_TEST); + glStencilFunc(GL_ALWAYS, 0, 0xff); + } + +#ifdef QT_GL_NO_SCISSOR_TEST + currentScissorBounds = QRect(0, 0, width, height); +#else + QRect bounds = q->state()->rectangleClip; + if (!q->state()->clipEnabled) { + if (useSystemClip) + bounds = systemClip.boundingRect(); + else + bounds = QRect(0, 0, width, height); + } else { + if (useSystemClip) + bounds = bounds.intersected(systemClip.boundingRect()); + else + bounds = bounds.intersected(QRect(0, 0, width, height)); + } + + currentScissorBounds = bounds; + + if (bounds == QRect(0, 0, width, height)) { + glDisable(GL_SCISSOR_TEST); + } else { + glEnable(GL_SCISSOR_TEST); + setScissor(bounds); + } +#endif +} + +void QOpenGL2PaintEngineExPrivate::setScissor(const QRect &rect) +{ + const int left = rect.left(); + const int width = rect.width(); + int bottom = height - (rect.top() + rect.height()); + if (device->isFlipped()) { + bottom = rect.top(); + } + const int height = rect.height(); + + glScissor(left, bottom, width, height); +} + +void QOpenGL2PaintEngineEx::clipEnabledChanged() +{ + Q_D(QOpenGL2PaintEngineEx); + + state()->clipChanged = true; + + if (painter()->hasClipping()) + d->regenerateClip(); + else + d->systemStateChanged(); +} + +void QOpenGL2PaintEngineExPrivate::clearClip(uint value) +{ + dirtyStencilRegion -= currentScissorBounds; + + glStencilMask(0xff); + glClearStencil(value); + glClear(GL_STENCIL_BUFFER_BIT); + glStencilMask(0x0); + + q->state()->needsClipBufferClear = false; +} + +void QOpenGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value) +{ + transferMode(BrushDrawingMode); + + if (snapToPixelGrid) { + snapToPixelGrid = false; + matrixDirty = true; + } + + if (matrixDirty) + updateMatrix(); + + stencilClean = false; + + const bool singlePass = !path.hasWindingFill() + && (((q->state()->currentClip == maxClip - 1) && q->state()->clipTestEnabled) + || q->state()->needsClipBufferClear); + const uint referenceClipValue = q->state()->needsClipBufferClear ? 1 : q->state()->currentClip; + + if (q->state()->needsClipBufferClear) + clearClip(1); + + if (path.isEmpty()) { + glEnable(GL_STENCIL_TEST); + glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT); + return; + } + + if (q->state()->clipTestEnabled) + glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); + else + glStencilFunc(GL_ALWAYS, 0, 0xff); + + vertexCoordinateArray.clear(); + vertexCoordinateArray.addPath(path, inverseScale, false); + + if (!singlePass) + fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); + + glColorMask(false, false, false, false); + glEnable(GL_STENCIL_TEST); + useSimpleShader(); + + if (singlePass) { + // Under these conditions we can set the new stencil value in a single + // pass, by using the current value and the "new value" as the toggles + + glStencilFunc(GL_LEQUAL, referenceClipValue, ~GL_STENCIL_HIGH_BIT); + glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); + glStencilMask(value ^ referenceClipValue); + + drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); + } else { + glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); + glStencilMask(0xff); + + if (!q->state()->clipTestEnabled && path.hasWindingFill()) { + // Pass when any clip bit is set, set high bit + glStencilFunc(GL_NOTEQUAL, GL_STENCIL_HIGH_BIT, ~GL_STENCIL_HIGH_BIT); + composite(vertexCoordinateArray.boundingRect()); + } + + // Pass when high bit is set, replace stencil value with new clip value + glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT); + + composite(vertexCoordinateArray.boundingRect()); + } + + glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT); + glStencilMask(0); + + glColorMask(true, true, true, true); +} + +void QOpenGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) +{ +// qDebug("QOpenGL2PaintEngineEx::clip()"); + Q_D(QOpenGL2PaintEngineEx); + + state()->clipChanged = true; + + ensureActive(); + + if (op == Qt::ReplaceClip) { + op = Qt::IntersectClip; + if (d->hasClipOperations()) { + d->systemStateChanged(); + state()->canRestoreClip = false; + } + } + +#ifndef QT_GL_NO_SCISSOR_TEST + if (!path.isEmpty() && op == Qt::IntersectClip && (path.shape() == QVectorPath::RectangleHint)) { + const QPointF* const points = reinterpret_cast(path.points()); + QRectF rect(points[0], points[2]); + + if (state()->matrix.type() <= QTransform::TxScale + || (state()->matrix.type() == QTransform::TxRotate + && qFuzzyIsNull(state()->matrix.m11()) + && qFuzzyIsNull(state()->matrix.m22()))) + { + state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect()); + d->updateClipScissorTest(); + return; + } + } +#endif + + const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect(); + + switch (op) { + case Qt::NoClip: + if (d->useSystemClip) { + state()->clipTestEnabled = true; + state()->currentClip = 1; + } else { + state()->clipTestEnabled = false; + } + state()->rectangleClip = QRect(0, 0, d->width, d->height); + state()->canRestoreClip = false; + d->updateClipScissorTest(); + break; + case Qt::IntersectClip: + state()->rectangleClip = state()->rectangleClip.intersected(pathRect); + d->updateClipScissorTest(); + d->resetClipIfNeeded(); + ++d->maxClip; + d->writeClip(path, d->maxClip); + state()->currentClip = d->maxClip; + state()->clipTestEnabled = true; + break; + default: + break; + } +} + +void QOpenGL2PaintEngineExPrivate::regenerateClip() +{ + systemStateChanged(); + replayClipOperations(); +} + +void QOpenGL2PaintEngineExPrivate::systemStateChanged() +{ + Q_Q(QOpenGL2PaintEngineEx); + + q->state()->clipChanged = true; + + if (systemClip.isEmpty()) { + useSystemClip = false; + } else { + if (q->paintDevice()->devType() == QInternal::Widget && currentClipDevice) { + //QWidgetPrivate *widgetPrivate = qt_widget_private(static_cast(currentClipDevice)->window()); + //useSystemClip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter; + useSystemClip = true; + } else { + useSystemClip = true; + } + } + + q->state()->clipTestEnabled = false; + q->state()->needsClipBufferClear = true; + + q->state()->currentClip = 1; + maxClip = 1; + + q->state()->rectangleClip = useSystemClip ? systemClip.boundingRect() : QRect(0, 0, width, height); + updateClipScissorTest(); + + if (systemClip.rectCount() == 1) { + if (systemClip.boundingRect() == QRect(0, 0, width, height)) + useSystemClip = false; +#ifndef QT_GL_NO_SCISSOR_TEST + // scissoring takes care of the system clip + return; +#endif + } + + if (useSystemClip) { + clearClip(0); + + QPainterPath path; + path.addRegion(systemClip); + + q->state()->currentClip = 0; + writeClip(qtVectorPathForPath(q->state()->matrix.inverted().map(path)), 1); + q->state()->currentClip = 1; + q->state()->clipTestEnabled = true; + } +} + +void QOpenGL2PaintEngineEx::setState(QPainterState *new_state) +{ + // qDebug("QOpenGL2PaintEngineEx::setState()"); + + Q_D(QOpenGL2PaintEngineEx); + + QOpenGL2PaintEngineState *s = static_cast(new_state); + QOpenGL2PaintEngineState *old_state = state(); + + QPaintEngineEx::setState(s); + + if (s->isNew) { + // Newly created state object. The call to setState() + // will either be followed by a call to begin(), or we are + // setting the state as part of a save(). + s->isNew = false; + return; + } + + // Setting the state as part of a restore(). + + if (old_state == s || old_state->renderHintsChanged) + renderHintsChanged(); + + if (old_state == s || old_state->matrixChanged) + d->matrixDirty = true; + + if (old_state == s || old_state->compositionModeChanged) + d->compositionModeDirty = true; + + if (old_state == s || old_state->opacityChanged) + d->opacityUniformDirty = true; + + if (old_state == s || old_state->clipChanged) { + if (old_state && old_state != s && old_state->canRestoreClip) { + d->updateClipScissorTest(); + glDepthFunc(GL_LEQUAL); + } else { + d->regenerateClip(); + } + } +} + +QPainterState *QOpenGL2PaintEngineEx::createState(QPainterState *orig) const +{ + if (orig) + const_cast(this)->ensureActive(); + + QOpenGL2PaintEngineState *s; + if (!orig) + s = new QOpenGL2PaintEngineState(); + else + s = new QOpenGL2PaintEngineState(*static_cast(orig)); + + s->matrixChanged = false; + s->compositionModeChanged = false; + s->opacityChanged = false; + s->renderHintsChanged = false; + s->clipChanged = false; + + return s; +} + +QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other) + : QPainterState(other) +{ + isNew = true; + needsClipBufferClear = other.needsClipBufferClear; + clipTestEnabled = other.clipTestEnabled; + currentClip = other.currentClip; + canRestoreClip = other.canRestoreClip; + rectangleClip = other.rectangleClip; +} + +QOpenGL2PaintEngineState::QOpenGL2PaintEngineState() +{ + isNew = true; + needsClipBufferClear = true; + clipTestEnabled = false; + canRestoreClip = true; +} + +QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() +{ +} + +void QOpenGL2PaintEngineExPrivate::setVertexAttribArrayEnabled(int arrayIndex, bool enabled) +{ + Q_ASSERT(arrayIndex < QT_GL_VERTEX_ARRAY_TRACKED_COUNT); + + if (vertexAttributeArraysEnabledState[arrayIndex] && !enabled) + funcs.glDisableVertexAttribArray(arrayIndex); + + if (!vertexAttributeArraysEnabledState[arrayIndex] && enabled) + funcs.glEnableVertexAttribArray(arrayIndex); + + vertexAttributeArraysEnabledState[arrayIndex] = enabled; +} + +void QOpenGL2PaintEngineExPrivate::syncGlState() +{ + for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) { + if (vertexAttributeArraysEnabledState[i]) + funcs.glEnableVertexAttribArray(i); + else + funcs.glDisableVertexAttribArray(i); + } +} + + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qpaintengineex_opengl2_p.h b/src/gui/opengl/qpaintengineex_opengl2_p.h new file mode 100644 index 0000000000..cea5cc1302 --- /dev/null +++ b/src/gui/opengl/qpaintengineex_opengl2_p.h @@ -0,0 +1,338 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSCONTEXT_OPENGL2_P_H +#define QGRAPHICSCONTEXT_OPENGL2_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +enum EngineMode { + ImageDrawingMode, + TextDrawingMode, + BrushDrawingMode, + ImageArrayDrawingMode +}; + +QT_BEGIN_NAMESPACE + +#define GL_STENCIL_HIGH_BIT GLuint(0x80) +#define QT_BRUSH_TEXTURE_UNIT GLuint(0) +#define QT_IMAGE_TEXTURE_UNIT GLuint(0) //Can be the same as brush texture unit +#define QT_MASK_TEXTURE_UNIT GLuint(1) +#define QT_BACKGROUND_TEXTURE_UNIT GLuint(2) + +class QOpenGL2PaintEngineExPrivate; + +class QOpenGL2PaintEngineState : public QPainterState +{ +public: + QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other); + QOpenGL2PaintEngineState(); + ~QOpenGL2PaintEngineState(); + + uint isNew : 1; + uint needsClipBufferClear : 1; + uint clipTestEnabled : 1; + uint canRestoreClip : 1; + uint matrixChanged : 1; + uint compositionModeChanged : 1; + uint opacityChanged : 1; + uint renderHintsChanged : 1; + uint clipChanged : 1; + uint currentClip : 8; + + QRect rectangleClip; +}; + +class Q_GUI_EXPORT QOpenGL2PaintEngineEx : public QPaintEngineEx +{ + Q_DECLARE_PRIVATE(QOpenGL2PaintEngineEx) +public: + QOpenGL2PaintEngineEx(); + ~QOpenGL2PaintEngineEx(); + + bool begin(QPaintDevice *device); + void ensureActive(); + bool end(); + + virtual void clipEnabledChanged(); + virtual void penChanged(); + virtual void brushChanged(); + virtual void brushOriginChanged(); + virtual void opacityChanged(); + virtual void compositionModeChanged(); + virtual void renderHintsChanged(); + virtual void transformChanged(); + + virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); + virtual void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, + QPainter::PixmapFragmentHints hints); + virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, + Qt::ImageConversionFlags flags = Qt::AutoColor); + virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); + virtual void fill(const QVectorPath &path, const QBrush &brush); + virtual void stroke(const QVectorPath &path, const QPen &pen); + virtual void clip(const QVectorPath &path, Qt::ClipOperation op); + + virtual void drawStaticTextItem(QStaticTextItem *textItem); + + bool drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr); + + Type type() const { return OpenGL2; } + + virtual void setState(QPainterState *s); + virtual QPainterState *createState(QPainterState *orig) const; + inline QOpenGL2PaintEngineState *state() { + return static_cast(QPaintEngineEx::state()); + } + inline const QOpenGL2PaintEngineState *state() const { + return static_cast(QPaintEngineEx::state()); + } + + void beginNativePainting(); + void endNativePainting(); + + void invalidateState(); + + void setRenderTextActive(bool); + + bool isNativePaintingActive() const; + bool supportsTransformations(qreal, const QTransform &) const { return true; } + +private: + Q_DISABLE_COPY(QOpenGL2PaintEngineEx) + + friend class QOpenGLEngineShaderManager; +}; + +// This probably needs to grow to GL_MAX_VERTEX_ATTRIBS, but 3 is ok for now as that's +// all the GL2 engine uses: +#define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3 + +class QOpenGL2PaintEngineExPrivate : public QPaintEngineExPrivate +{ + Q_DECLARE_PUBLIC(QOpenGL2PaintEngineEx) +public: + enum StencilFillMode { + OddEvenFillMode, + WindingFillMode, + TriStripStrokeFillMode + }; + + QOpenGL2PaintEngineExPrivate(QOpenGL2PaintEngineEx *q_ptr) : + q(q_ptr), + shaderManager(0), + width(0), height(0), + ctx(0), + useSystemClip(true), + elementIndicesVBOId(0), + opacityArray(0), + snapToPixelGrid(false), + nativePaintingActive(false), + inverseScale(1), + lastMaskTextureUsed(0) + { } + + ~QOpenGL2PaintEngineExPrivate(); + + void updateBrushTexture(); + void updateBrushUniforms(); + void updateMatrix(); + void updateCompositionMode(); + void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id = -1); + + void resetGLState(); + + // fill, stroke, drawTexture, drawPixmaps & drawCachedGlyphs are the main rendering entry-points, + // however writeClip can also be thought of as en entry point as it does similar things. + void fill(const QVectorPath &path); + void stroke(const QVectorPath &path, const QPen &pen); + void drawTexture(const QOpenGLRect& dest, const QOpenGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); + void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, + QPainter::PixmapFragmentHints hints); + void drawCachedGlyphs(QFontEngineGlyphCache::Type glyphType, QStaticTextItem *staticTextItem); + + // Calls glVertexAttributePointer if the pointer has changed + inline void setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer); + + // draws whatever is in the vertex array: + void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive); + void drawVertexArrays(QOpenGL2PEXVertexArray &vertexArray, GLenum primitive) { + drawVertexArrays((const float *) vertexArray.data(), vertexArray.stops(), vertexArray.stopCount(), primitive); + } + + // Composites the bounding rect onto dest buffer: + void composite(const QOpenGLRect& boundingRect); + + // Calls drawVertexArrays to render into stencil buffer: + void fillStencilWithVertexArray(const float *data, int count, int *stops, int stopCount, const QOpenGLRect &bounds, StencilFillMode mode); + void fillStencilWithVertexArray(QOpenGL2PEXVertexArray& vertexArray, bool useWindingFill) { + fillStencilWithVertexArray((const float *) vertexArray.data(), 0, vertexArray.stops(), vertexArray.stopCount(), + vertexArray.boundingRect(), + useWindingFill ? WindingFillMode : OddEvenFillMode); + } + + void setBrush(const QBrush& brush); + void transferMode(EngineMode newMode); + bool prepareForDraw(bool srcPixelsAreOpaque); // returns true if the program has changed + inline void useSimpleShader(); + inline GLuint location(const QOpenGLEngineShaderManager::Uniform uniform) { + return shaderManager->getUniformLocation(uniform); + } + + void clearClip(uint value); + void writeClip(const QVectorPath &path, uint value); + void resetClipIfNeeded(); + + void updateClipScissorTest(); + void setScissor(const QRect &rect); + void regenerateClip(); + void systemStateChanged(); + + void setVertexAttribArrayEnabled(int arrayIndex, bool enabled = true); + void syncGlState(); + + static QOpenGLEngineShaderManager* shaderManagerForEngine(QOpenGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; } + static QOpenGL2PaintEngineExPrivate *getData(QOpenGL2PaintEngineEx *engine) { return engine->d_func(); } + static void cleanupVectorPath(QPaintEngineEx *engine, void *data); + + QOpenGLExtensions funcs; + + QOpenGL2PaintEngineEx* q; + QOpenGLEngineShaderManager* shaderManager; + QOpenGLPaintDevice* device; + int width, height; + QOpenGLContext *ctx; + EngineMode mode; + QFontEngineGlyphCache::Type glyphCacheType; + + bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT]; + + // Dirty flags + bool matrixDirty; // Implies matrix uniforms are also dirty + bool compositionModeDirty; + bool brushTextureDirty; + bool brushUniformsDirty; + bool opacityUniformDirty; + bool matrixUniformDirty; + + bool stencilClean; // Has the stencil not been used for clipping so far? + bool useSystemClip; + QRegion dirtyStencilRegion; + QRect currentScissorBounds; + uint maxClip; + + QBrush currentBrush; // May not be the state's brush! + const QBrush noBrush; + + QPixmap currentBrushPixmap; + + QOpenGL2PEXVertexArray vertexCoordinateArray; + QOpenGL2PEXVertexArray textureCoordinateArray; + QVector elementIndices; + GLuint elementIndicesVBOId; + QDataBuffer opacityArray; + GLfloat staticVertexCoordinateArray[8]; + GLfloat staticTextureCoordinateArray[8]; + + bool snapToPixelGrid; + bool nativePaintingActive; + GLfloat pmvMatrix[3][3]; + GLfloat inverseScale; + + GLuint lastTextureUsed; + GLuint lastMaskTextureUsed; + + bool needsSync; + bool multisamplingAlwaysEnabled; + + GLfloat depthRange[2]; + + float textureInvertedY; + + QTriangulatingStroker stroker; + QDashedStrokeProcessor dasher; + + QSet pathCaches; + QVector unusedVBOSToClean; + QVector unusedIBOSToClean; + + const GLfloat *vertexAttribPointers[3]; +}; + + +void QOpenGL2PaintEngineExPrivate::setVertexAttributePointer(unsigned int arrayIndex, const GLfloat *pointer) +{ + Q_ASSERT(arrayIndex < 3); + if (pointer == vertexAttribPointers[arrayIndex]) + return; + + vertexAttribPointers[arrayIndex] = pointer; + if (arrayIndex == QT_OPACITY_ATTR) + funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, pointer); + else + funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, pointer); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/opengl/qrbtree_p.h b/src/gui/opengl/qrbtree_p.h new file mode 100644 index 0000000000..ac464a3fbe --- /dev/null +++ b/src/gui/opengl/qrbtree_p.h @@ -0,0 +1,573 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QRBTREE_P_H +#define QRBTREE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +template +struct QRBTree +{ + struct Node + { + inline Node() : parent(0), left(0), right(0), red(true) { } + inline ~Node() {if (left) delete left; if (right) delete right;} + T data; + Node *parent; + Node *left; + Node *right; + bool red; + }; + + inline QRBTree() : root(0), freeList(0) { } + inline ~QRBTree(); + + inline void clear(); + + void attachBefore(Node *parent, Node *child); + void attachAfter(Node *parent, Node *child); + + inline Node *front(Node *node) const; + inline Node *back(Node *node) const; + Node *next(Node *node) const; + Node *previous(Node *node) const; + + inline void deleteNode(Node *&node); + inline Node *newNode(); + + // Return 1 if 'left' comes after 'right', 0 if equal, and -1 otherwise. + // 'left' and 'right' cannot be null. + int order(Node *left, Node *right); + inline bool validate() const; + +private: + void rotateLeft(Node *node); + void rotateRight(Node *node); + void update(Node *node); + + inline void attachLeft(Node *parent, Node *child); + inline void attachRight(Node *parent, Node *child); + + int blackDepth(Node *top) const; + bool checkRedBlackProperty(Node *top) const; + + void swapNodes(Node *n1, Node *n2); + void detach(Node *node); + + // 'node' must be black. rebalance will reduce the depth of black nodes by one in the sibling tree. + void rebalance(Node *node); + +public: + Node *root; +private: + Node *freeList; +}; + +template +inline QRBTree::~QRBTree() +{ + clear(); + while (freeList) { + // Avoid recursively calling the destructor, as this list may become large. + Node *next = freeList->right; + freeList->right = 0; + delete freeList; + freeList = next; + } +} + +template +inline void QRBTree::clear() +{ + if (root) + delete root; + root = 0; +} + +template +void QRBTree::rotateLeft(Node *node) +{ + // | | // + // N B // + // / \ / \ // + // A B ---> N D // + // / \ / \ // + // C D A C // + + Node *&ref = (node->parent ? (node == node->parent->left ? node->parent->left : node->parent->right) : root); + ref = node->right; + node->right->parent = node->parent; + + // : // + // N // + // / :| // + // A B // + // / \ // + // C D // + + node->right = ref->left; + if (ref->left) + ref->left->parent = node; + + // : | // + // N B // + // / \ : \ // + // A C D // + + ref->left = node; + node->parent = ref; + + // | // + // B // + // / \ // + // N D // + // / \ // + // A C // +} + +template +void QRBTree::rotateRight(Node *node) +{ + // | | // + // N A // + // / \ / \ // + // A B ---> C N // + // / \ / \ // + // C D D B // + + Node *&ref = (node->parent ? (node == node->parent->left ? node->parent->left : node->parent->right) : root); + ref = node->left; + node->left->parent = node->parent; + + node->left = ref->right; + if (ref->right) + ref->right->parent = node; + + ref->right = node; + node->parent = ref; +} + +template +void QRBTree::update(Node *node) // call this after inserting a node +{ + for (;;) { + Node *parent = node->parent; + + // if the node is the root, color it black + if (!parent) { + node->red = false; + return; + } + + // if the parent is black, the node can be left red + if (!parent->red) + return; + + // at this point, the parent is red and cannot be the root + Node *grandpa = parent->parent; + Q_ASSERT(grandpa); + + Node *uncle = (parent == grandpa->left ? grandpa->right : grandpa->left); + if (uncle && uncle->red) { + // grandpa's black, parent and uncle are red. + // let parent and uncle be black, grandpa red and recursively update grandpa. + Q_ASSERT(!grandpa->red); + parent->red = false; + uncle->red = false; + grandpa->red = true; + node = grandpa; + continue; + } + + // at this point, uncle is black + if (node == parent->right && parent == grandpa->left) + rotateLeft(node = parent); + else if (node == parent->left && parent == grandpa->right) + rotateRight(node = parent); + parent = node->parent; + + if (parent == grandpa->left) { + rotateRight(grandpa); + parent->red = false; + grandpa->red = true; + } else { + rotateLeft(grandpa); + parent->red = false; + grandpa->red = true; + } + return; + } +} + +template +inline void QRBTree::attachLeft(Node *parent, Node *child) +{ + Q_ASSERT(!parent->left); + parent->left = child; + child->parent = parent; + update(child); +} + +template +inline void QRBTree::attachRight(Node *parent, Node *child) +{ + Q_ASSERT(!parent->right); + parent->right = child; + child->parent = parent; + update(child); +} + +template +void QRBTree::attachBefore(Node *parent, Node *child) +{ + if (!root) + update(root = child); + else if (!parent) + attachRight(back(root), child); + else if (parent->left) + attachRight(back(parent->left), child); + else + attachLeft(parent, child); +} + +template +void QRBTree::attachAfter(Node *parent, Node *child) +{ + if (!root) + update(root = child); + else if (!parent) + attachLeft(front(root), child); + else if (parent->right) + attachLeft(front(parent->right), child); + else + attachRight(parent, child); +} + +template +void QRBTree::swapNodes(Node *n1, Node *n2) +{ + // Since iterators must not be invalidated, it is not sufficient to only swap the data. + if (n1->parent == n2) { + n1->parent = n2->parent; + n2->parent = n1; + } else if (n2->parent == n1) { + n2->parent = n1->parent; + n1->parent = n2; + } else { + qSwap(n1->parent, n2->parent); + } + + qSwap(n1->left, n2->left); + qSwap(n1->right, n2->right); + qSwap(n1->red, n2->red); + + if (n1->parent) { + if (n1->parent->left == n2) + n1->parent->left = n1; + else + n1->parent->right = n1; + } else { + root = n1; + } + + if (n2->parent) { + if (n2->parent->left == n1) + n2->parent->left = n2; + else + n2->parent->right = n2; + } else { + root = n2; + } + + if (n1->left) + n1->left->parent = n1; + if (n1->right) + n1->right->parent = n1; + + if (n2->left) + n2->left->parent = n2; + if (n2->right) + n2->right->parent = n2; +} + +template +void QRBTree::detach(Node *node) // call this before removing a node. +{ + if (node->right) + swapNodes(node, front(node->right)); + + Node *child = (node->left ? node->left : node->right); + + if (!node->red) { + if (child && child->red) + child->red = false; + else + rebalance(node); + } + + Node *&ref = (node->parent ? (node == node->parent->left ? node->parent->left : node->parent->right) : root); + ref = child; + if (child) + child->parent = node->parent; + node->left = node->right = node->parent = 0; +} + +// 'node' must be black. rebalance will reduce the depth of black nodes by one in the sibling tree. +template +void QRBTree::rebalance(Node *node) +{ + Q_ASSERT(!node->red); + for (;;) { + if (!node->parent) + return; + + // at this point, node is not a parent, it is black, thus it must have a sibling. + Node *sibling = (node == node->parent->left ? node->parent->right : node->parent->left); + Q_ASSERT(sibling); + + if (sibling->red) { + sibling->red = false; + node->parent->red = true; + if (node == node->parent->left) + rotateLeft(node->parent); + else + rotateRight(node->parent); + sibling = (node == node->parent->left ? node->parent->right : node->parent->left); + Q_ASSERT(sibling); + } + + // at this point, the sibling is black. + Q_ASSERT(!sibling->red); + + if ((!sibling->left || !sibling->left->red) && (!sibling->right || !sibling->right->red)) { + bool parentWasRed = node->parent->red; + sibling->red = true; + node->parent->red = false; + if (parentWasRed) + return; + node = node->parent; + continue; + } + + // at this point, at least one of the sibling's children is red. + + if (node == node->parent->left) { + if (!sibling->right || !sibling->right->red) { + Q_ASSERT(sibling->left); + sibling->red = true; + sibling->left->red = false; + rotateRight(sibling); + + sibling = sibling->parent; + Q_ASSERT(sibling); + } + sibling->red = node->parent->red; + node->parent->red = false; + + Q_ASSERT(sibling->right->red); + sibling->right->red = false; + rotateLeft(node->parent); + } else { + if (!sibling->left || !sibling->left->red) { + Q_ASSERT(sibling->right); + sibling->red = true; + sibling->right->red = false; + rotateLeft(sibling); + + sibling = sibling->parent; + Q_ASSERT(sibling); + } + sibling->red = node->parent->red; + node->parent->red = false; + + Q_ASSERT(sibling->left->red); + sibling->left->red = false; + rotateRight(node->parent); + } + return; + } +} + +template +inline typename QRBTree::Node *QRBTree::front(Node *node) const +{ + while (node->left) + node = node->left; + return node; +} + +template +inline typename QRBTree::Node *QRBTree::back(Node *node) const +{ + while (node->right) + node = node->right; + return node; +} + +template +typename QRBTree::Node *QRBTree::next(Node *node) const +{ + if (node->right) + return front(node->right); + while (node->parent && node == node->parent->right) + node = node->parent; + return node->parent; +} + +template +typename QRBTree::Node *QRBTree::previous(Node *node) const +{ + if (node->left) + return back(node->left); + while (node->parent && node == node->parent->left) + node = node->parent; + return node->parent; +} + +template +int QRBTree::blackDepth(Node *top) const +{ + if (!top) + return 0; + int leftDepth = blackDepth(top->left); + int rightDepth = blackDepth(top->right); + if (leftDepth != rightDepth) + return -1; + if (!top->red) + ++leftDepth; + return leftDepth; +} + +template +bool QRBTree::checkRedBlackProperty(Node *top) const +{ + if (!top) + return true; + if (top->left && !checkRedBlackProperty(top->left)) + return false; + if (top->right && !checkRedBlackProperty(top->right)) + return false; + return !(top->red && ((top->left && top->left->red) || (top->right && top->right->red))); +} + +template +inline bool QRBTree::validate() const +{ + return checkRedBlackProperty(root) && blackDepth(root) != -1; +} + +template +inline void QRBTree::deleteNode(Node *&node) +{ + Q_ASSERT(node); + detach(node); + node->right = freeList; + freeList = node; + node = 0; +} + +template +inline typename QRBTree::Node *QRBTree::newNode() +{ + if (freeList) { + Node *node = freeList; + freeList = freeList->right; + node->parent = node->left = node->right = 0; + node->red = true; + return node; + } + return new Node; +} + +// Return 1 if 'left' comes after 'right', 0 if equal, and -1 otherwise. +// 'left' and 'right' cannot be null. +template +int QRBTree::order(Node *left, Node *right) +{ + Q_ASSERT(left && right); + if (left == right) + return 0; + + QVector leftAncestors; + QVector rightAncestors; + while (left) { + leftAncestors.push_back(left); + left = left->parent; + } + while (right) { + rightAncestors.push_back(right); + right = right->parent; + } + Q_ASSERT(leftAncestors.back() == root && rightAncestors.back() == root); + + while (!leftAncestors.empty() && !rightAncestors.empty() && leftAncestors.back() == rightAncestors.back()) { + leftAncestors.pop_back(); + rightAncestors.pop_back(); + } + + if (!leftAncestors.empty()) + return (leftAncestors.back() == leftAncestors.back()->parent->left ? -1 : 1); + + if (!rightAncestors.empty()) + return (rightAncestors.back() == rightAncestors.back()->parent->right ? -1 : 1); + + // The code should never reach this point. + Q_ASSERT(!leftAncestors.empty() || !rightAncestors.empty()); + return 0; +} + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/opengl/qtextureglyphcache_gl.cpp b/src/gui/opengl/qtextureglyphcache_gl.cpp new file mode 100644 index 0000000000..6da72d41ce --- /dev/null +++ b/src/gui/opengl/qtextureglyphcache_gl.cpp @@ -0,0 +1,396 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtextureglyphcache_gl_p.h" +#include "qpaintengineex_opengl2_p.h" +#include "private/qopenglengineshadersource_p.h" + +QT_BEGIN_NAMESPACE + +#ifdef Q_WS_WIN +extern Q_GUI_EXPORT bool qt_cleartype_enabled; +#endif + +QBasicAtomicInt qopengltextureglyphcache_serial_number = Q_BASIC_ATOMIC_INITIALIZER(1); + +QOpenGLTextureGlyphCache::QOpenGLTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix) + : QImageTextureGlyphCache(type, matrix) + , pex(0) + , m_blitProgram(0) + , m_filterMode(Nearest) + , m_serialNumber(qopengltextureglyphcache_serial_number.fetchAndAddRelaxed(1)) +{ +#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG + qDebug(" -> QOpenGLTextureGlyphCache() %p for context %p.", this, QOpenGLContext::currentContext()); +#endif + m_vertexCoordinateArray[0] = -1.0f; + m_vertexCoordinateArray[1] = -1.0f; + m_vertexCoordinateArray[2] = 1.0f; + m_vertexCoordinateArray[3] = -1.0f; + m_vertexCoordinateArray[4] = 1.0f; + m_vertexCoordinateArray[5] = 1.0f; + m_vertexCoordinateArray[6] = -1.0f; + m_vertexCoordinateArray[7] = 1.0f; + + m_textureCoordinateArray[0] = 0.0f; + m_textureCoordinateArray[1] = 0.0f; + m_textureCoordinateArray[2] = 1.0f; + m_textureCoordinateArray[3] = 0.0f; + m_textureCoordinateArray[4] = 1.0f; + m_textureCoordinateArray[5] = 1.0f; + m_textureCoordinateArray[6] = 0.0f; + m_textureCoordinateArray[7] = 1.0f; +} + +QOpenGLTextureGlyphCache::~QOpenGLTextureGlyphCache() +{ +#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG + qDebug(" -> ~QOpenGLTextureGlyphCache() %p.", this); +#endif + delete m_blitProgram; +} + +void QOpenGLTextureGlyphCache::createTextureData(int width, int height) +{ + QOpenGLContext *ctx = const_cast(QOpenGLContext::currentContext()); + if (ctx == 0) { + qWarning("QOpenGLTextureGlyphCache::createTextureData: Called with no context"); + return; + } + + // create in QImageTextureGlyphCache baseclass is meant to be called + // only to create the initial image and does not preserve the content, + // so we don't call when this function is called from resize. + if (ctx->d_func()->workaround_brokenFBOReadBack && image().isNull()) + QImageTextureGlyphCache::createTextureData(width, height); + + // Make the lower glyph texture size 16 x 16. + if (width < 16) + width = 16; + if (height < 16) + height = 16; + + if (m_textureResource && !m_textureResource->m_texture) + delete m_textureResource; + + if (!m_textureResource) + m_textureResource = new QOpenGLGlyphTexture(ctx); + + glGenTextures(1, &m_textureResource->m_texture); + glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); + + m_textureResource->m_width = width; + m_textureResource->m_height = height; + + if (m_type == QFontEngineGlyphCache::Raster_RGBMask) { + QVarLengthArray data(width * height * 4); + for (int i = 0; i < data.size(); ++i) + data[i] = 0; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + } else { + QVarLengthArray data(width * height); + for (int i = 0; i < data.size(); ++i) + data[i] = 0; + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]); + } + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + m_filterMode = Nearest; +} + +void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height) +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (ctx == 0) { + qWarning("QOpenGLTextureGlyphCache::resizeTextureData: Called with no context"); + return; + } + + int oldWidth = m_textureResource->m_width; + int oldHeight = m_textureResource->m_height; + + // Make the lower glyph texture size 16 x 16. + if (width < 16) + width = 16; + if (height < 16) + height = 16; + + GLuint oldTexture = m_textureResource->m_texture; + createTextureData(width, height); + + if (ctx->d_func()->workaround_brokenFBOReadBack) { + QImageTextureGlyphCache::resizeTextureData(width, height); + Q_ASSERT(image().depth() == 8); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, image().constBits()); + glDeleteTextures(1, &oldTexture); + return; + } + + // ### the QTextureGlyphCache API needs to be reworked to allow + // ### resizeTextureData to fail + + QOpenGLFunctions funcs(ctx); + + funcs.glBindFramebuffer(GL_FRAMEBUFFER, m_textureResource->m_fbo); + + GLuint tmp_texture; + glGenTextures(1, &tmp_texture); + glBindTexture(GL_TEXTURE_2D, tmp_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + 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_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + m_filterMode = Nearest; + glBindTexture(GL_TEXTURE_2D, 0); + funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, tmp_texture, 0); + + funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, oldTexture); + + if (pex != 0) + pex->transferMode(BrushDrawingMode); + + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + + glViewport(0, 0, oldWidth, oldHeight); + + QOpenGLShaderProgram *blitProgram = 0; + if (pex == 0) { + if (m_blitProgram == 0) { + m_blitProgram = new QOpenGLShaderProgram(ctx); + + { + QString source; + source.append(QLatin1String(qopenglslMainWithTexCoordsVertexShader)); + source.append(QLatin1String(qopenglslUntransformedPositionVertexShader)); + + QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram); + vertexShader->compileSourceCode(source); + + m_blitProgram->addShader(vertexShader); + } + + { + QString source; + source.append(QLatin1String(qopenglslMainFragmentShader)); + source.append(QLatin1String(qopenglslImageSrcFragmentShader)); + + QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram); + fragmentShader->compileSourceCode(source); + + m_blitProgram->addShader(fragmentShader); + } + + m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + + m_blitProgram->link(); + } + + funcs.glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_vertexCoordinateArray); + funcs.glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_textureCoordinateArray); + + m_blitProgram->bind(); + m_blitProgram->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR)); + m_blitProgram->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR)); + m_blitProgram->disableAttributeArray(int(QT_OPACITY_ATTR)); + + blitProgram = m_blitProgram; + + } else { + pex->setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, m_vertexCoordinateArray); + pex->setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, m_textureCoordinateArray); + + pex->shaderManager->useBlitProgram(); + blitProgram = pex->shaderManager->blitProgram(); + } + + blitProgram->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); + + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); + + funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, 0); + glDeleteTextures(1, &tmp_texture); + glDeleteTextures(1, &oldTexture); + + funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo); + + if (pex != 0) { + glViewport(0, 0, pex->width, pex->height); + pex->updateClipScissorTest(); + } +} + +void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition) +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (ctx == 0) { + qWarning("QOpenGLTextureGlyphCache::fillTexture: Called with no context"); + return; + } + + if (ctx->d_func()->workaround_brokenFBOReadBack) { + QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition); + + glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); + const QImage &texture = image(); + const uchar *bits = texture.constBits(); + bits += c.y * texture.bytesPerLine() + c.x; + for (int i=0; i> 16; + uchar g = src[x] >> 8; + uchar b = src[x]; + quint32 avg = (quint32(r) + quint32(g) + quint32(b) + 1) / 3; // "+1" for rounding. + src[x] = (src[x] & 0x00ffffff) | (avg << 24); + } + } + } + + glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); + if (mask.format() == QImage::Format_RGB32) { + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits()); + } else { + // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is + // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista + // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a + // multiple of four bytes per line, and most of the glyph shows up correctly in the + // texture, which makes me think that this is a driver bug. + // One workaround is to make sure the mask width is a multiple of four bytes, for instance + // by converting it to a format with four bytes per pixel. Another is to copy one line at a + // time. + +#if 0 + if (!ctx->d_func()->workaround_brokenAlphaTexSubImage_init) { + // don't know which driver versions exhibit this bug, so be conservative for now + const QByteArray versionString(reinterpret_cast(glGetString(GL_VERSION))); + glctx->d_func()->workaround_brokenAlphaTexSubImage = versionString.indexOf("NVIDIA") >= 0; + glctx->d_func()->workaround_brokenAlphaTexSubImage_init = true; + } +#endif + +#if 0 + if (ctx->d_func()->workaround_brokenAlphaTexSubImage) { + for (int i = 0; i < maskHeight; ++i) + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i)); + } else { +#endif + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits()); +// } + } +} + +int QOpenGLTextureGlyphCache::glyphPadding() const +{ + return 1; +} + +int QOpenGLTextureGlyphCache::maxTextureWidth() const +{ + QOpenGLContext *ctx = const_cast(QOpenGLContext::currentContext()); + if (ctx == 0) + return QImageTextureGlyphCache::maxTextureWidth(); + else + return ctx->d_func()->maxTextureSize(); +} + +int QOpenGLTextureGlyphCache::maxTextureHeight() const +{ + QOpenGLContext *ctx = const_cast(QOpenGLContext::currentContext()); + if (ctx == 0) + return QImageTextureGlyphCache::maxTextureHeight(); + + if (ctx->d_func()->workaround_brokenTexSubImage) + return qMin(1024, ctx->d_func()->maxTextureSize()); + else + return ctx->d_func()->maxTextureSize(); +} + +void QOpenGLTextureGlyphCache::clear() +{ + m_textureResource->free(); + m_textureResource = 0; + + m_w = 0; + m_h = 0; + m_cx = 0; + m_cy = 0; + m_currentRowHeight = 0; + coords.clear(); +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qtextureglyphcache_gl_p.h b/src/gui/opengl/qtextureglyphcache_gl_p.h new file mode 100644 index 0000000000..cf157e07df --- /dev/null +++ b/src/gui/opengl/qtextureglyphcache_gl_p.h @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTEXTUREGLYPHCACHE_GL_P_H +#define QTEXTUREGLYPHCACHE_GL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +// #define QT_GL_TEXTURE_GLYPH_CACHE_DEBUG + +QT_BEGIN_NAMESPACE + +class QOpenGL2PaintEngineExPrivate; + +struct QOpenGLGlyphTexture : public QOpenGLSharedResource +{ + QOpenGLGlyphTexture(QOpenGLContext *ctx) + : QOpenGLSharedResource(ctx->shareGroup()) + , m_width(0) + , m_height(0) + { + if (ctx && !ctx->d_func()->workaround_brokenFBOReadBack) + QOpenGLFunctions(ctx).glGenFramebuffers(1, &m_fbo); + +#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG + qDebug(" -> QOpenGLGlyphTexture() %p for context %p.", this, ctx); +#endif + } + + void freeResource(QOpenGLContext *context) + { + QOpenGLContext *ctx = context; +#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG + qDebug("~QOpenGLGlyphTexture() %p for context %p.", this, ctx); +#endif + if (!ctx->d_func()->workaround_brokenFBOReadBack) + QOpenGLFunctions(ctx).glDeleteFramebuffers(1, &m_fbo); + if (m_width || m_height) + glDeleteTextures(1, &m_texture); + } + + void invalidateResource() + { + m_texture = 0; + m_fbo = 0; + m_width = 0; + m_height = 0; + } + + GLuint m_texture; + GLuint m_fbo; + int m_width; + int m_height; +}; + +class Q_GUI_EXPORT QOpenGLTextureGlyphCache : public QImageTextureGlyphCache +{ +public: + QOpenGLTextureGlyphCache(QFontEngineGlyphCache::Type type, const QTransform &matrix); + ~QOpenGLTextureGlyphCache(); + + virtual void createTextureData(int width, int height); + virtual void resizeTextureData(int width, int height); + virtual void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition); + virtual int glyphPadding() const; + virtual int maxTextureWidth() const; + virtual int maxTextureHeight() const; + + inline GLuint texture() const { + QOpenGLTextureGlyphCache *that = const_cast(this); + QOpenGLGlyphTexture *glyphTexture = that->m_textureResource; + return glyphTexture ? glyphTexture->m_texture : 0; + } + + inline int width() const { + QOpenGLTextureGlyphCache *that = const_cast(this); + QOpenGLGlyphTexture *glyphTexture = that->m_textureResource; + return glyphTexture ? glyphTexture->m_width : 0; + } + inline int height() const { + QOpenGLTextureGlyphCache *that = const_cast(this); + QOpenGLGlyphTexture *glyphTexture = that->m_textureResource; + return glyphTexture ? glyphTexture->m_height : 0; + } + + inline void setPaintEnginePrivate(QOpenGL2PaintEngineExPrivate *p) { pex = p; } + + inline const QOpenGLContextGroup *contextGroup() const { return m_textureResource ? m_textureResource->group() : 0; } + + inline int serialNumber() const { return m_serialNumber; } + + enum FilterMode { + Nearest, + Linear + }; + FilterMode filterMode() const { return m_filterMode; } + void setFilterMode(FilterMode m) { m_filterMode = m; } + + void clear(); + +private: + QOpenGLGlyphTexture *m_textureResource; + + QOpenGL2PaintEngineExPrivate *pex; + QOpenGLShaderProgram *m_blitProgram; + FilterMode m_filterMode; + + GLfloat m_vertexCoordinateArray[8]; + GLfloat m_textureCoordinateArray[8]; + + int m_serialNumber; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/src/gui/opengl/qtriangulatingstroker.cpp b/src/gui/opengl/qtriangulatingstroker.cpp new file mode 100644 index 0000000000..2bd01a4307 --- /dev/null +++ b/src/gui/opengl/qtriangulatingstroker.cpp @@ -0,0 +1,588 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtriangulatingstroker_p.h" +#include + +QT_BEGIN_NAMESPACE + +#define CURVE_FLATNESS Q_PI / 8 + + + + +void QTriangulatingStroker::endCapOrJoinClosed(const qreal *start, const qreal *cur, + bool implicitClose, bool endsAtStart) +{ + if (endsAtStart) { + join(start + 2); + } else if (implicitClose) { + join(start); + lineTo(start); + join(start+2); + } else { + endCap(cur); + } + int count = m_vertices.size(); + + // Copy the (x, y) values because QDataBuffer::add(const float& t) + // may resize the buffer, which will leave t pointing at the + // previous buffer's memory region if we don't copy first. + float x = m_vertices.at(count-2); + float y = m_vertices.at(count-1); + m_vertices.add(x); + m_vertices.add(y); +} + + +void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, const QRectF &) +{ + const qreal *pts = path.points(); + const QPainterPath::ElementType *types = path.elements(); + int count = path.elementCount(); + if (count < 2) + return; + + float realWidth = qpen_widthf(pen); + if (realWidth == 0) + realWidth = 1; + + m_width = realWidth / 2; + + bool cosmetic = pen.isCosmetic(); + if (cosmetic) { + m_width = m_width * m_inv_scale; + } + + m_join_style = qpen_joinStyle(pen); + m_cap_style = qpen_capStyle(pen); + m_vertices.reset(); + m_miter_limit = pen.miterLimit() * qpen_widthf(pen); + + // The curvyness is based on the notion that I originally wanted + // roughly one line segment pr 4 pixels. This may seem little, but + // because we sample at constantly incrementing B(t) E [0(4, realWidth * CURVE_FLATNESS); + } else { + m_curvyness_add = m_width; + m_curvyness_mul = CURVE_FLATNESS / m_inv_scale; + m_roundness = qMax(4, realWidth * m_curvyness_mul); + } + + // Over this level of segmentation, there doesn't seem to be any + // benefit, even for huge penWidth + if (m_roundness > 24) + m_roundness = 24; + + m_sin_theta = qFastSin(Q_PI / m_roundness); + m_cos_theta = qFastCos(Q_PI / m_roundness); + + const qreal *endPts = pts + (count<<1); + const qreal *startPts = 0; + + Qt::PenCapStyle cap = m_cap_style; + + if (!types) { + // skip duplicate points + while((pts + 2) < endPts && pts[0] == pts[2] && pts[1] == pts[3]) + pts += 2; + if ((pts + 2) == endPts) + return; + + startPts = pts; + + bool endsAtStart = startPts[0] == *(endPts-2) && startPts[1] == *(endPts-1); + + if (endsAtStart || path.hasImplicitClose()) + m_cap_style = Qt::FlatCap; + moveTo(pts); + m_cap_style = cap; + pts += 2; + lineTo(pts); + pts += 2; + while (pts < endPts) { + if (m_cx != pts[0] || m_cy != pts[1]) { + join(pts); + lineTo(pts); + } + pts += 2; + } + + endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart); + + } else { + bool endsAtStart = false; + while (pts < endPts) { + switch (*types) { + case QPainterPath::MoveToElement: { + if (pts != path.points()) + endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart); + + startPts = pts; + int end = (endPts - pts) / 2; + int i = 2; // Start looking to ahead since we never have two moveto's in a row + while (i points; + arcPoints(m_cx, m_cy, m_cx + m_nvx, m_cy + m_nvy, m_cx - m_nvx, m_cy - m_nvy, points); + m_vertices.resize(m_vertices.size() + points.size() + 2 * int(invisibleJump)); + int count = m_vertices.size(); + int front = 0; + int end = points.size() / 2; + while (front != end) { + m_vertices.at(--count) = points[2 * end - 1]; + m_vertices.at(--count) = points[2 * end - 2]; + --end; + if (front == end) + break; + m_vertices.at(--count) = points[2 * front + 1]; + m_vertices.at(--count) = points[2 * front + 0]; + ++front; + } + + if (invisibleJump) { + m_vertices.at(count - 1) = m_vertices.at(count + 1); + m_vertices.at(count - 2) = m_vertices.at(count + 0); + } + break; } + default: break; // ssssh gcc... + } + emitLineSegment(m_cx, m_cy, m_nvx, m_nvy); +} + +void QTriangulatingStroker::cubicTo(const qreal *pts) +{ + const QPointF *p = (const QPointF *) pts; + QBezier bezier = QBezier::fromPoints(*(p - 1), p[0], p[1], p[2]); + + QRectF bounds = bezier.bounds(); + float rad = qMax(bounds.width(), bounds.height()); + int threshold = qMin(64, (rad + m_curvyness_add) * m_curvyness_mul); + if (threshold < 4) + threshold = 4; + qreal threshold_minus_1 = threshold - 1; + float vx, vy; + + float cx = m_cx, cy = m_cy; + float x, y; + + for (int i=1; i (pts[0], pts[1]) + normalVector(m_cx, m_cy, pts[0], pts[1], &m_nvx, &m_nvy); + + switch (m_join_style) { + case Qt::BevelJoin: + break; + case Qt::SvgMiterJoin: + case Qt::MiterJoin: { + // Find out on which side the join should be. + int count = m_vertices.size(); + float prevNvx = m_vertices.at(count - 2) - m_cx; + float prevNvy = m_vertices.at(count - 1) - m_cy; + float xprod = prevNvx * m_nvy - prevNvy * m_nvx; + float px, py, qx, qy; + + // If the segments are parallel, use bevel join. + if (qFuzzyIsNull(xprod)) + break; + + // Find the corners of the previous and next segment to join. + if (xprod < 0) { + px = m_vertices.at(count - 2); + py = m_vertices.at(count - 1); + qx = m_cx - m_nvx; + qy = m_cy - m_nvy; + } else { + px = m_vertices.at(count - 4); + py = m_vertices.at(count - 3); + qx = m_cx + m_nvx; + qy = m_cy + m_nvy; + } + + // Find intersection point. + float pu = px * prevNvx + py * prevNvy; + float qv = qx * m_nvx + qy * m_nvy; + float ix = (m_nvy * pu - prevNvy * qv) / xprod; + float iy = (prevNvx * qv - m_nvx * pu) / xprod; + + // Check that the distance to the intersection point is less than the miter limit. + if ((ix - px) * (ix - px) + (iy - py) * (iy - py) <= m_miter_limit * m_miter_limit) { + m_vertices.add(ix); + m_vertices.add(iy); + m_vertices.add(ix); + m_vertices.add(iy); + } + // else + // Do a plain bevel join if the miter limit is exceeded or if + // the lines are parallel. This is not what the raster + // engine's stroker does, but it is both faster and similar to + // what some other graphics API's do. + + break; } + case Qt::RoundJoin: { + QVarLengthArray points; + int count = m_vertices.size(); + float prevNvx = m_vertices.at(count - 2) - m_cx; + float prevNvy = m_vertices.at(count - 1) - m_cy; + if (m_nvx * prevNvy - m_nvy * prevNvx < 0) { + arcPoints(0, 0, m_nvx, m_nvy, -prevNvx, -prevNvy, points); + for (int i = points.size() / 2; i > 0; --i) + emitLineSegment(m_cx, m_cy, points[2 * i - 2], points[2 * i - 1]); + } else { + arcPoints(0, 0, -prevNvx, -prevNvy, m_nvx, m_nvy, points); + for (int i = 0; i < points.size() / 2; ++i) + emitLineSegment(m_cx, m_cy, points[2 * i + 0], points[2 * i + 1]); + } + break; } + default: break; // gcc warn-- + } + + emitLineSegment(m_cx, m_cy, m_nvx, m_nvy); +} + +void QTriangulatingStroker::endCap(const qreal *) +{ + switch (m_cap_style) { + case Qt::FlatCap: + break; + case Qt::SquareCap: + emitLineSegment(m_cx + m_nvy, m_cy - m_nvx, m_nvx, m_nvy); + break; + case Qt::RoundCap: { + QVarLengthArray points; + int count = m_vertices.size(); + arcPoints(m_cx, m_cy, m_vertices.at(count - 2), m_vertices.at(count - 1), m_vertices.at(count - 4), m_vertices.at(count - 3), points); + int front = 0; + int end = points.size() / 2; + while (front != end) { + m_vertices.add(points[2 * end - 2]); + m_vertices.add(points[2 * end - 1]); + --end; + if (front == end) + break; + m_vertices.add(points[2 * front + 0]); + m_vertices.add(points[2 * front + 1]); + ++front; + } + break; } + default: break; // to shut gcc up... + } +} + +void QTriangulatingStroker::arcPoints(float cx, float cy, float fromX, float fromY, float toX, float toY, QVarLengthArray &points) +{ + float dx1 = fromX - cx; + float dy1 = fromY - cy; + float dx2 = toX - cx; + float dy2 = toY - cy; + + // while more than 180 degrees left: + while (dx1 * dy2 - dx2 * dy1 < 0) { + float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta; + float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta; + dx1 = tmpx; + dy1 = tmpy; + points.append(cx + dx1); + points.append(cy + dy1); + } + + // while more than 90 degrees left: + while (dx1 * dx2 + dy1 * dy2 < 0) { + float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta; + float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta; + dx1 = tmpx; + dy1 = tmpy; + points.append(cx + dx1); + points.append(cy + dy1); + } + + // while more than 0 degrees left: + while (dx1 * dy2 - dx2 * dy1 > 0) { + float tmpx = dx1 * m_cos_theta - dy1 * m_sin_theta; + float tmpy = dx1 * m_sin_theta + dy1 * m_cos_theta; + dx1 = tmpx; + dy1 = tmpy; + points.append(cx + dx1); + points.append(cy + dy1); + } + + // remove last point which was rotated beyond [toX, toY]. + if (!points.isEmpty()) + points.resize(points.size() - 2); +} + +static void qdashprocessor_moveTo(qreal x, qreal y, void *data) +{ + ((QDashedStrokeProcessor *) data)->addElement(QPainterPath::MoveToElement, x, y); +} + +static void qdashprocessor_lineTo(qreal x, qreal y, void *data) +{ + ((QDashedStrokeProcessor *) data)->addElement(QPainterPath::LineToElement, x, y); +} + +static void qdashprocessor_cubicTo(qreal, qreal, qreal, qreal, qreal, qreal, void *) +{ + Q_ASSERT(0); // The dasher should not produce curves... +} + +QDashedStrokeProcessor::QDashedStrokeProcessor() + : m_points(0), m_types(0), + m_dash_stroker(0), m_inv_scale(1) +{ + m_dash_stroker.setMoveToHook(qdashprocessor_moveTo); + m_dash_stroker.setLineToHook(qdashprocessor_lineTo); + m_dash_stroker.setCubicToHook(qdashprocessor_cubicTo); +} + +void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen, const QRectF &clip) +{ + + const qreal *pts = path.points(); + const QPainterPath::ElementType *types = path.elements(); + int count = path.elementCount(); + + bool cosmetic = pen.isCosmetic(); + + m_points.reset(); + m_types.reset(); + m_points.reserve(path.elementCount()); + m_types.reserve(path.elementCount()); + + qreal width = qpen_widthf(pen); + if (width == 0) + width = 1; + + m_dash_stroker.setDashPattern(pen.dashPattern()); + m_dash_stroker.setStrokeWidth(cosmetic ? width * m_inv_scale : width); + m_dash_stroker.setDashOffset(pen.dashOffset()); + m_dash_stroker.setMiterLimit(pen.miterLimit()); + m_dash_stroker.setClipRect(clip); + + float curvynessAdd, curvynessMul, roundness = 0; + + // simplfy pens that are thin in device size (2px wide or less) + if (width < 2.5 && (cosmetic || m_inv_scale == 1)) { + curvynessAdd = 0.5; + curvynessMul = CURVE_FLATNESS / m_inv_scale; + roundness = 1; + } else if (cosmetic) { + curvynessAdd= width / 2; + curvynessMul= CURVE_FLATNESS; + roundness = qMax(4, width * CURVE_FLATNESS); + } else { + curvynessAdd = width * m_inv_scale; + curvynessMul = CURVE_FLATNESS / m_inv_scale; + roundness = qMax(4, width * curvynessMul); + } + + if (count < 2) + return; + + const qreal *endPts = pts + (count<<1); + + m_dash_stroker.begin(this); + + if (!types) { + m_dash_stroker.moveTo(pts[0], pts[1]); + pts += 2; + while (pts < endPts) { + m_dash_stroker.lineTo(pts[0], pts[1]); + pts += 2; + } + } else { + while (pts < endPts) { + switch (*types) { + case QPainterPath::MoveToElement: + m_dash_stroker.moveTo(pts[0], pts[1]); + pts += 2; + ++types; + break; + case QPainterPath::LineToElement: + m_dash_stroker.lineTo(pts[0], pts[1]); + pts += 2; + ++types; + break; + case QPainterPath::CurveToElement: { + QBezier b = QBezier::fromPoints(*(((const QPointF *) pts) - 1), + *(((const QPointF *) pts)), + *(((const QPointF *) pts) + 1), + *(((const QPointF *) pts) + 2)); + QRectF bounds = b.bounds(); + float rad = qMax(bounds.width(), bounds.height()); + int threshold = qMin(64, (rad + curvynessAdd) * curvynessMul); + if (threshold < 4) + threshold = 4; + + qreal threshold_minus_1 = threshold - 1; + for (int i=0; i +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QTriangulatingStroker +{ +public: + QTriangulatingStroker() : m_vertices(0) {} + void process(const QVectorPath &path, const QPen &pen, const QRectF &clip); + + inline int vertexCount() const { return m_vertices.size(); } + inline const float *vertices() const { return m_vertices.data(); } + + inline void setInvScale(qreal invScale) { m_inv_scale = invScale; } + +private: + inline void emitLineSegment(float x, float y, float nx, float ny); + void moveTo(const qreal *pts); + inline void lineTo(const qreal *pts); + void cubicTo(const qreal *pts); + void join(const qreal *pts); + inline void normalVector(float x1, float y1, float x2, float y2, float *nx, float *ny); + void endCap(const qreal *pts); + void arcPoints(float cx, float cy, float fromX, float fromY, float toX, float toY, QVarLengthArray &points); + void endCapOrJoinClosed(const qreal *start, const qreal *cur, bool implicitClose, bool endsAtStart); + + + QDataBuffer m_vertices; + + float m_cx, m_cy; // current points + float m_nvx, m_nvy; // normal vector... + float m_width; + qreal m_miter_limit; + + int m_roundness; // Number of line segments in a round join + qreal m_sin_theta; // sin(m_roundness / 360); + qreal m_cos_theta; // cos(m_roundness / 360); + qreal m_inv_scale; + float m_curvyness_mul; + float m_curvyness_add; + + Qt::PenJoinStyle m_join_style; + Qt::PenCapStyle m_cap_style; +}; + +class QDashedStrokeProcessor +{ +public: + QDashedStrokeProcessor(); + + void process(const QVectorPath &path, const QPen &pen, const QRectF &clip); + + inline void addElement(QPainterPath::ElementType type, qreal x, qreal y) { + m_points.add(x); + m_points.add(y); + m_types.add(type); + } + + inline int elementCount() const { return m_types.size(); } + inline qreal *points() const { return m_points.data(); } + inline QPainterPath::ElementType *elementTypes() const { return m_types.data(); } + + inline void setInvScale(qreal invScale) { m_inv_scale = invScale; } + +private: + QDataBuffer m_points; + QDataBuffer m_types; + QDashStroker m_dash_stroker; + qreal m_inv_scale; +}; + +inline void QTriangulatingStroker::normalVector(float x1, float y1, float x2, float y2, + float *nx, float *ny) +{ + float dx = x2 - x1; + float dy = y2 - y1; + + float pw; + + if (dx == 0) + pw = m_width / qAbs(dy); + else if (dy == 0) + pw = m_width / qAbs(dx); + else + pw = m_width / sqrt(dx*dx + dy*dy); + + *nx = -dy * pw; + *ny = dx * pw; +} + +inline void QTriangulatingStroker::emitLineSegment(float x, float y, float vx, float vy) +{ + m_vertices.add(x + vx); + m_vertices.add(y + vy); + m_vertices.add(x - vx); + m_vertices.add(y - vy); +} + +void QTriangulatingStroker::lineTo(const qreal *pts) +{ + emitLineSegment(pts[0], pts[1], m_nvx, m_nvy); + m_cx = pts[0]; + m_cy = pts[1]; +} + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/opengl/qtriangulator.cpp b/src/gui/opengl/qtriangulator.cpp new file mode 100644 index 0000000000..dbbae4d938 --- /dev/null +++ b/src/gui/opengl/qtriangulator.cpp @@ -0,0 +1,2622 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtriangulator_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +//#define Q_TRIANGULATOR_DEBUG + +#define Q_FIXED_POINT_SCALE 32 + +// Quick sort. +template +#ifdef Q_CC_RVCT // RVCT 2.2 doesn't see recursive _static_ template function +void sort(T *array, int count, LessThan lessThan) +#else +static void sort(T *array, int count, LessThan lessThan) +#endif +{ + // If the number of elements fall below some threshold, use insertion sort. + const int INSERTION_SORT_LIMIT = 7; // About 7 is fastest on my computer... + if (count <= INSERTION_SORT_LIMIT) { + for (int i = 1; i < count; ++i) { + T temp = array[i]; + int j = i; + while (j > 0 && lessThan(temp, array[j - 1])) { + array[j] = array[j - 1]; + --j; + } + array[j] = temp; + } + return; + } + + int high = count - 1; + int low = 0; + int mid = high / 2; + if (lessThan(array[mid], array[low])) + qSwap(array[mid], array[low]); + if (lessThan(array[high], array[mid])) + qSwap(array[high], array[mid]); + if (lessThan(array[mid], array[low])) + qSwap(array[mid], array[low]); + + --high; + ++low; + qSwap(array[mid], array[high]); + int pivot = high; + --high; + + while (low <= high) { + while (!lessThan(array[pivot], array[low])) { + ++low; + if (low > high) + goto sort_loop_end; + } + while (!lessThan(array[high], array[pivot])) { + --high; + if (low > high) + goto sort_loop_end; + } + qSwap(array[low], array[high]); + ++low; + --high; + } +sort_loop_end: + if (low != pivot) + qSwap(array[pivot], array[low]); + sort(array, low, lessThan); + sort(array + low + 1, count - low - 1, lessThan); +} + +// Quick sort. +template +#ifdef Q_CC_RVCT +void sort(T *array, int count) // RVCT 2.2 doesn't see recursive _static_ template function +#else +static void sort(T *array, int count) +#endif +{ + // If the number of elements fall below some threshold, use insertion sort. + const int INSERTION_SORT_LIMIT = 25; // About 25 is fastest on my computer... + if (count <= INSERTION_SORT_LIMIT) { + for (int i = 1; i < count; ++i) { + T temp = array[i]; + int j = i; + while (j > 0 && (temp < array[j - 1])) { + array[j] = array[j - 1]; + --j; + } + array[j] = temp; + } + return; + } + + int high = count - 1; + int low = 0; + int mid = high / 2; + if ((array[mid] < array[low])) + qSwap(array[mid], array[low]); + if ((array[high] < array[mid])) + qSwap(array[high], array[mid]); + if ((array[mid] < array[low])) + qSwap(array[mid], array[low]); + + --high; + ++low; + qSwap(array[mid], array[high]); + int pivot = high; + --high; + + while (low <= high) { + while (!(array[pivot] < array[low])) { + ++low; + if (low > high) + goto sort_loop_end; + } + while (!(array[high] < array[pivot])) { + --high; + if (low > high) + goto sort_loop_end; + } + qSwap(array[low], array[high]); + ++low; + --high; + } +sort_loop_end: + if (low != pivot) + qSwap(array[pivot], array[low]); + sort(array, low); + sort(array + low + 1, count - low - 1); +} + +template +struct QVertexSet +{ + inline QVertexSet() { } + inline QVertexSet(const QVertexSet &other) : vertices(other.vertices), indices(other.indices) { } + QVertexSet &operator = (const QVertexSet &other) {vertices = other.vertices; indices = other.indices; return *this;} + + // The vertices of a triangle are given by: (x[i[n]], y[i[n]]), (x[j[n]], y[j[n]]), (x[k[n]], y[k[n]]), n = 0, 1, ... + QVector vertices; // [x[0], y[0], x[1], y[1], x[2], ...] + QVector indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...] +}; + +//============================================================================// +// QFraction // +//============================================================================// + +// Fraction must be in the range [0, 1) +struct QFraction +{ + // Comparison operators must not be called on invalid fractions. + inline bool operator < (const QFraction &other) const; + inline bool operator == (const QFraction &other) const; + inline bool operator != (const QFraction &other) const {return !(*this == other);} + inline bool operator > (const QFraction &other) const {return other < *this;} + inline bool operator >= (const QFraction &other) const {return !(*this < other);} + inline bool operator <= (const QFraction &other) const {return !(*this > other);} + + inline bool isValid() const {return denominator != 0;} + + // numerator and denominator must not have common denominators. + quint64 numerator, denominator; +}; + +static inline quint64 gcd(quint64 x, quint64 y) +{ + while (y != 0) { + quint64 z = y; + y = x % y; + x = z; + } + return x; +} + +static inline int compare(quint64 a, quint64 b) +{ + return (a > b) - (a < b); +} + +// Compare a/b with c/d. +// Return negative if less, 0 if equal, positive if greater. +// a < b, c < d +static int qCompareFractions(quint64 a, quint64 b, quint64 c, quint64 d) +{ + const quint64 LIMIT = Q_UINT64_C(0x100000000); + for (;;) { + // If the products 'ad' and 'bc' fit into 64 bits, they can be directly compared. + if (b < LIMIT && d < LIMIT) + return compare(a * d, b * c); + + if (a == 0 || c == 0) + return compare(a, c); + + // a/b < c/d <=> d/c < b/a + quint64 b_div_a = b / a; + quint64 d_div_c = d / c; + if (b_div_a != d_div_c) + return compare(d_div_c, b_div_a); + + // floor(d/c) == floor(b/a) + // frac(d/c) < frac(b/a) ? + // frac(x/y) = (x%y)/y + d -= d_div_c * c; //d %= c; + b -= b_div_a * a; //b %= a; + qSwap(a, d); + qSwap(b, c); + } +} + +// Fraction must be in the range [0, 1) +// Assume input is valid. +static QFraction qFraction(quint64 n, quint64 d) { + QFraction result; + if (n == 0) { + result.numerator = 0; + result.denominator = 1; + } else { + quint64 g = gcd(n, d); + result.numerator = n / g; + result.denominator = d / g; + } + return result; +} + +inline bool QFraction::operator < (const QFraction &other) const +{ + return qCompareFractions(numerator, denominator, other.numerator, other.denominator) < 0; +} + +inline bool QFraction::operator == (const QFraction &other) const +{ + return numerator == other.numerator && denominator == other.denominator; +} + +//============================================================================// +// QPodPoint // +//============================================================================// + +struct QPodPoint +{ + inline bool operator < (const QPodPoint &other) const + { + if (y != other.y) + return y < other.y; + return x < other.x; + } + + inline bool operator > (const QPodPoint &other) const {return other < *this;} + inline bool operator <= (const QPodPoint &other) const {return !(*this > other);} + inline bool operator >= (const QPodPoint &other) const {return !(*this < other);} + inline bool operator == (const QPodPoint &other) const {return x == other.x && y == other.y;} + inline bool operator != (const QPodPoint &other) const {return x != other.x || y != other.y;} + + inline QPodPoint &operator += (const QPodPoint &other) {x += other.x; y += other.y; return *this;} + inline QPodPoint &operator -= (const QPodPoint &other) {x -= other.x; y -= other.y; return *this;} + inline QPodPoint operator + (const QPodPoint &other) const {QPodPoint result = {x + other.x, y + other.y}; return result;} + inline QPodPoint operator - (const QPodPoint &other) const {QPodPoint result = {x - other.x, y - other.y}; return result;} + + int x; + int y; +}; + +static inline qint64 qCross(const QPodPoint &u, const QPodPoint &v) +{ + return qint64(u.x) * qint64(v.y) - qint64(u.y) * qint64(v.x); +} + +static inline qint64 qDot(const QPodPoint &u, const QPodPoint &v) +{ + return qint64(u.x) * qint64(v.x) + qint64(u.y) * qint64(v.y); +} + +// Return positive value if 'p' is to the right of the line 'v1'->'v2', negative if left of the +// line and zero if exactly on the line. +// The returned value is the z-component of the qCross product between 'v2-v1' and 'p-v1', +// which is twice the signed area of the triangle 'p'->'v1'->'v2' (positive for CW order). +static inline qint64 qPointDistanceFromLine(const QPodPoint &p, const QPodPoint &v1, const QPodPoint &v2) +{ + return qCross(v2 - v1, p - v1); +} + +static inline bool qPointIsLeftOfLine(const QPodPoint &p, const QPodPoint &v1, const QPodPoint &v2) +{ + return QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(p, v1, v2) < 0; +} + +// Return: +// -1 if u < v +// 0 if u == v +// 1 if u > v +static int comparePoints(const QPodPoint &u, const QPodPoint &v) +{ + if (u.y < v.y) + return -1; + if (u.y > v.y) + return 1; + if (u.x < v.x) + return -1; + if (u.x > v.x) + return 1; + return 0; +} + +//============================================================================// +// QIntersectionPoint // +//============================================================================// + +struct QIntersectionPoint +{ + inline bool isValid() const {return xOffset.isValid() && yOffset.isValid();} + QPodPoint round() const; + inline bool isAccurate() const {return xOffset.numerator == 0 && yOffset.numerator == 0;} + bool operator < (const QIntersectionPoint &other) const; + bool operator == (const QIntersectionPoint &other) const; + inline bool operator != (const QIntersectionPoint &other) const {return !(*this == other);} + inline bool operator > (const QIntersectionPoint &other) const {return other < *this;} + inline bool operator >= (const QIntersectionPoint &other) const {return !(*this < other);} + inline bool operator <= (const QIntersectionPoint &other) const {return !(*this > other);} + bool isOnLine(const QPodPoint &u, const QPodPoint &v) const; + + QPodPoint upperLeft; + QFraction xOffset; + QFraction yOffset; +}; + +static inline QIntersectionPoint qIntersectionPoint(const QPodPoint &point) +{ + // upperLeft = point, xOffset = 0/1, yOffset = 0/1. + QIntersectionPoint p = {{point.x, point.y}, {0, 1}, {0, 1}}; + return p; +} + +static inline QIntersectionPoint qIntersectionPoint(int x, int y) +{ + // upperLeft = (x, y), xOffset = 0/1, yOffset = 0/1. + QIntersectionPoint p = {{x, y}, {0, 1}, {0, 1}}; + return p; +} + +static QIntersectionPoint qIntersectionPoint(const QPodPoint &u1, const QPodPoint &u2, const QPodPoint &v1, const QPodPoint &v2) +{ + QIntersectionPoint result = {{0, 0}, {0, 0}, {0, 0}}; + + QPodPoint u = u2 - u1; + QPodPoint v = v2 - v1; + qint64 d1 = qCross(u, v1 - u1); + qint64 d2 = qCross(u, v2 - u1); + qint64 det = d2 - d1; + qint64 d3 = qCross(v, u1 - v1); + qint64 d4 = d3 - det; //qCross(v, u2 - v1); + + // Check that the math is correct. + Q_ASSERT(d4 == qCross(v, u2 - v1)); + + // The intersection point can be expressed as: + // v1 - v * d1/det + // v2 - v * d2/det + // u1 + u * d3/det + // u2 + u * d4/det + + // I'm only interested in lines that are crossing, so ignore parallel lines even if they overlap. + if (det == 0) + return result; + + if (det < 0) { + det = -det; + d1 = -d1; + d2 = -d2; + d3 = -d3; + d4 = -d4; + } + + // I'm only interested in lines intersecting at their interior, not at their end points. + // The lines intersect at their interior if and only if 'd1 < 0', 'd2 > 0', 'd3 < 0' and 'd4 > 0'. + if (d1 >= 0 || d2 <= 0 || d3 <= 0 || d4 >= 0) + return result; + + // Calculate the intersection point as follows: + // v1 - v * d1/det | v1 <= v2 (component-wise) + // v2 - v * d2/det | v2 < v1 (component-wise) + + // Assuming 21 bits per vector component. + // TODO: Make code path for 31 bits per vector component. + if (v.x >= 0) { + result.upperLeft.x = v1.x + (-v.x * d1) / det; + result.xOffset = qFraction(quint64(-v.x * d1) % quint64(det), quint64(det)); + } else { + result.upperLeft.x = v2.x + (-v.x * d2) / det; + result.xOffset = qFraction(quint64(-v.x * d2) % quint64(det), quint64(det)); + } + + if (v.y >= 0) { + result.upperLeft.y = v1.y + (-v.y * d1) / det; + result.yOffset = qFraction(quint64(-v.y * d1) % quint64(det), quint64(det)); + } else { + result.upperLeft.y = v2.y + (-v.y * d2) / det; + result.yOffset = qFraction(quint64(-v.y * d2) % quint64(det), quint64(det)); + } + + Q_ASSERT(result.xOffset.isValid()); + Q_ASSERT(result.yOffset.isValid()); + return result; +} + +QPodPoint QIntersectionPoint::round() const +{ + QPodPoint result = upperLeft; + if (2 * xOffset.numerator >= xOffset.denominator) + ++result.x; + if (2 * yOffset.numerator >= yOffset.denominator) + ++result.y; + return result; +} + +bool QIntersectionPoint::operator < (const QIntersectionPoint &other) const +{ + if (upperLeft.y != other.upperLeft.y) + return upperLeft.y < other.upperLeft.y; + if (yOffset != other.yOffset) + return yOffset < other.yOffset; + if (upperLeft.x != other.upperLeft.x) + return upperLeft.x < other.upperLeft.x; + return xOffset < other.xOffset; +} + +bool QIntersectionPoint::operator == (const QIntersectionPoint &other) const +{ + return upperLeft == other.upperLeft && xOffset == other.xOffset && yOffset == other.yOffset; +} + +// Returns true if this point is on the infinite line passing through 'u' and 'v'. +bool QIntersectionPoint::isOnLine(const QPodPoint &u, const QPodPoint &v) const +{ + // TODO: Make code path for coordinates with more than 21 bits. + const QPodPoint p = upperLeft - u; + const QPodPoint q = v - u; + bool isHorizontal = p.y == 0 && yOffset.numerator == 0; + bool isVertical = p.x == 0 && xOffset.numerator == 0; + if (isHorizontal && isVertical) + return true; + if (isHorizontal) + return q.y == 0; + if (q.y == 0) + return false; + if (isVertical) + return q.x == 0; + if (q.x == 0) + return false; + + // At this point, 'p+offset' and 'q' cannot lie on the x or y axis. + + if (((q.x < 0) == (q.y < 0)) != ((p.x < 0) == (p.y < 0))) + return false; // 'p + offset' and 'q' pass through different quadrants. + + // Move all coordinates into the first quadrant. + quint64 nx, ny; + if (p.x < 0) + nx = quint64(-p.x) * xOffset.denominator - xOffset.numerator; + else + nx = quint64(p.x) * xOffset.denominator + xOffset.numerator; + if (p.y < 0) + ny = quint64(-p.y) * yOffset.denominator - yOffset.numerator; + else + ny = quint64(p.y) * yOffset.denominator + yOffset.numerator; + + return qFraction(quint64(qAbs(q.x)) * xOffset.denominator, quint64(qAbs(q.y)) * yOffset.denominator) == qFraction(nx, ny); +} + +//============================================================================// +// QMaxHeap // +//============================================================================// + +template +class QMaxHeap +{ +public: + QMaxHeap() : m_data(0) {} + inline int size() const {return m_data.size();} + inline bool empty() const {return m_data.isEmpty();} + inline bool isEmpty() const {return m_data.isEmpty();} + void push(const T &x); + T pop(); + inline const T &top() const {return m_data.first();} +private: + static inline int parent(int i) {return (i - 1) / 2;} + static inline int left(int i) {return 2 * i + 1;} + static inline int right(int i) {return 2 * i + 2;} + + QDataBuffer m_data; +}; + +template +void QMaxHeap::push(const T &x) +{ + int current = m_data.size(); + int parent = QMaxHeap::parent(current); + m_data.add(x); + while (current != 0 && m_data.at(parent) < x) { + m_data.at(current) = m_data.at(parent); + current = parent; + parent = QMaxHeap::parent(current); + } + m_data.at(current) = x; +} + +template +T QMaxHeap::pop() +{ + T result = m_data.first(); + T back = m_data.last(); + m_data.pop_back(); + if (!m_data.isEmpty()) { + int current = 0; + for (;;) { + int left = QMaxHeap::left(current); + int right = QMaxHeap::right(current); + if (left >= m_data.size()) + break; + int greater = left; + if (right < m_data.size() && m_data.at(left) < m_data.at(right)) + greater = right; + if (m_data.at(greater) < back) + break; + m_data.at(current) = m_data.at(greater); + current = greater; + } + m_data.at(current) = back; + } + return result; +} + +//============================================================================// +// QInt64Hash // +//============================================================================// + +// Copied from qhash.cpp +static const uchar prime_deltas[] = { + 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3, + 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0 +}; + +// Copied from qhash.cpp +static inline int primeForNumBits(int numBits) +{ + return (1 << numBits) + prime_deltas[numBits]; +} + +static inline int primeForCount(int count) +{ + int low = 0; + int high = 32; + for (int i = 0; i < 5; ++i) { + int mid = (high + low) / 2; + if (count >= 1 << mid) + low = mid; + else + high = mid; + } + return primeForNumBits(high); +} + +// Hash set of quint64s. Elements cannot be removed without clearing the +// entire set. A value of -1 is used to mark unused entries. +class QInt64Set +{ +public: + inline QInt64Set(int capacity = 64); + inline ~QInt64Set() {if (m_array) delete[] m_array;} + inline bool isValid() const {return m_array;} + void insert(quint64 key); + bool contains(quint64 key) const; + inline void clear(); +private: + bool rehash(int capacity); + + static const quint64 UNUSED; + + quint64 *m_array; + int m_capacity; + int m_count; +}; + +const quint64 QInt64Set::UNUSED = quint64(-1); + +inline QInt64Set::QInt64Set(int capacity) +{ + m_capacity = primeForCount(capacity); + m_array = new quint64[m_capacity]; + if (m_array) + clear(); + else + m_capacity = 0; +} + +bool QInt64Set::rehash(int capacity) +{ + quint64 *oldArray = m_array; + int oldCapacity = m_capacity; + + m_capacity = capacity; + m_array = new quint64[m_capacity]; + if (m_array) { + clear(); + if (oldArray) { + for (int i = 0; i < oldCapacity; ++i) { + if (oldArray[i] != UNUSED) + insert(oldArray[i]); + } + delete[] oldArray; + } + return true; + } else { + m_capacity = oldCapacity; + m_array = oldArray; + return false; + } +} + +void QInt64Set::insert(quint64 key) +{ + if (m_count > 3 * m_capacity / 4) + rehash(primeForCount(2 * m_capacity)); + Q_ASSERT_X(m_array, "QInt64Hash::insert", "Hash set not allocated."); + int index = int(key % m_capacity); + for (int i = 0; i < m_capacity; ++i) { + index += i; + if (index >= m_capacity) + index -= m_capacity; + if (m_array[index] == key) + return; + if (m_array[index] == UNUSED) { + ++m_count; + m_array[index] = key; + return; + } + } + Q_ASSERT_X(0, "QInt64Hash::insert", "Hash set full."); +} + +bool QInt64Set::contains(quint64 key) const +{ + Q_ASSERT_X(m_array, "QInt64Hash::contains", "Hash set not allocated."); + int index = int(key % m_capacity); + for (int i = 0; i < m_capacity; ++i) { + index += i; + if (index >= m_capacity) + index -= m_capacity; + if (m_array[index] == key) + return true; + if (m_array[index] == UNUSED) + return false; + } + return false; +} + +inline void QInt64Set::clear() +{ + Q_ASSERT_X(m_array, "QInt64Hash::clear", "Hash set not allocated."); + for (int i = 0; i < m_capacity; ++i) + m_array[i] = UNUSED; + m_count = 0; +} + +//============================================================================// +// QRingBuffer // +//============================================================================// + +// T must be POD. +template +class QRingBuffer +{ +public: + inline QRingBuffer() : m_array(0), m_head(0), m_size(0), m_capacity(0) { } + inline ~QRingBuffer() {if (m_array) delete[] m_array;} + bool reallocate(int capacity); + inline const T &head() const {Q_ASSERT(m_size > 0); return m_array[m_head];} + inline const T &dequeue(); + inline void enqueue(const T &x); + inline bool isEmpty() const {return m_size == 0;} +private: + T *m_array; + int m_head; + int m_size; + int m_capacity; +}; + +template +bool QRingBuffer::reallocate(int capacity) +{ + T *oldArray = m_array; + m_array = new T[capacity]; + if (m_array) { + if (oldArray) { + if (m_head + m_size > m_capacity) { + memcpy(m_array, oldArray + m_head, (m_capacity - m_head) * sizeof(T)); + memcpy(m_array + (m_capacity - m_head), oldArray, (m_head + m_size - m_capacity) * sizeof(T)); + } else { + memcpy(m_array, oldArray + m_head, m_size * sizeof(T)); + } + delete[] oldArray; + } + m_capacity = capacity; + m_head = 0; + return true; + } else { + m_array = oldArray; + return false; + } +} + +template +inline const T &QRingBuffer::dequeue() +{ + Q_ASSERT(m_size > 0); + Q_ASSERT(m_array); + Q_ASSERT(m_capacity >= m_size); + int index = m_head; + if (++m_head >= m_capacity) + m_head -= m_capacity; + --m_size; + return m_array[index]; +} + +template +inline void QRingBuffer::enqueue(const T &x) +{ + if (m_size == m_capacity) + reallocate(qMax(2 * m_capacity, 64)); + int index = m_head + m_size; + if (index >= m_capacity) + index -= m_capacity; + m_array[index] = x; + ++m_size; +} + +//============================================================================// +// QTriangulator // +//============================================================================// +template +class QTriangulator +{ +public: + typedef QVarLengthArray ShortArray; + + //================================// + // QTriangulator::ComplexToSimple // + //================================// + friend class ComplexToSimple; + class ComplexToSimple + { + public: + inline ComplexToSimple(QTriangulator *parent) : m_parent(parent), + m_edges(0), m_events(0), m_splits(0) { } + void decompose(); + private: + struct Edge + { + inline int &upper() {return pointingUp ? to : from;} + inline int &lower() {return pointingUp ? from : to;} + inline int upper() const {return pointingUp ? to : from;} + inline int lower() const {return pointingUp ? from : to;} + + QRBTree::Node *node; + int from, to; // vertex + int next, previous; // edge + int winding; + bool mayIntersect; + bool pointingUp, originallyPointingUp; + }; + + friend class CompareEdges; + class CompareEdges + { + public: + inline CompareEdges(ComplexToSimple *parent) : m_parent(parent) { } + bool operator () (int i, int j) const; + private: + ComplexToSimple *m_parent; + }; + + struct Intersection + { + bool operator < (const Intersection &other) const {return other.intersectionPoint < intersectionPoint;} + + QIntersectionPoint intersectionPoint; + int vertex; + int leftEdge; + int rightEdge; + }; + + struct Split + { + int vertex; + int edge; + bool accurate; + }; + + struct Event + { + enum Type {Upper, Lower}; + inline bool operator < (const Event &other) const; + + QPodPoint point; + Type type; + int edge; + }; + +#ifdef Q_TRIANGULATOR_DEBUG + friend class DebugDialog; + friend class QTriangulator; + class DebugDialog : public QDialog + { + public: + DebugDialog(ComplexToSimple *parent, int currentVertex); + protected: + void paintEvent(QPaintEvent *); + void wheelEvent(QWheelEvent *); + void mouseMoveEvent(QMouseEvent *); + void mousePressEvent(QMouseEvent *); + private: + ComplexToSimple *m_parent; + QRectF m_window; + QPoint m_lastMousePos; + int m_vertex; + }; +#endif + + void initEdges(); + bool calculateIntersection(int left, int right); + bool edgeIsLeftOfEdge(int leftEdgeIndex, int rightEdgeIndex) const; + QRBTree::Node *searchEdgeLeftOf(int edgeIndex) const; + QRBTree::Node *searchEdgeLeftOf(int edgeIndex, QRBTree::Node *after) const; + QPair::Node *, QRBTree::Node *> bounds(const QPodPoint &point) const; + QPair::Node *, QRBTree::Node *> outerBounds(const QPodPoint &point) const; + void splitEdgeListRange(QRBTree::Node *leftmost, QRBTree::Node *rightmost, int vertex, const QIntersectionPoint &intersectionPoint); + void reorderEdgeListRange(QRBTree::Node *leftmost, QRBTree::Node *rightmost); + void sortEdgeList(const QPodPoint eventPoint); + void fillPriorityQueue(); + void calculateIntersections(); + int splitEdge(int splitIndex); + bool splitEdgesAtIntersections(); + void insertEdgeIntoVectorIfWanted(ShortArray &orderedEdges, int i); + void removeUnwantedEdgesAndConnect(); + void removeUnusedPoints(); + + QTriangulator *m_parent; + QDataBuffer m_edges; + QRBTree m_edgeList; + QDataBuffer m_events; + QDataBuffer m_splits; + QMaxHeap m_topIntersection; + QInt64Set m_processedEdgePairs; + int m_initialPointCount; + }; +#ifdef Q_TRIANGULATOR_DEBUG + friend class ComplexToSimple::DebugDialog; +#endif + + //=================================// + // QTriangulator::SimpleToMonotone // + //=================================// + friend class SimpleToMonotone; + class SimpleToMonotone + { + public: + inline SimpleToMonotone(QTriangulator *parent) : m_parent(parent), m_edges(0), m_upperVertex(0) { } + void decompose(); + private: + enum VertexType {MergeVertex, EndVertex, RegularVertex, StartVertex, SplitVertex}; + + struct Edge + { + QRBTree::Node *node; + int helper, twin, next, previous; + T from, to; + VertexType type; + bool pointingUp; + int upper() const {return (pointingUp ? to : from);} + int lower() const {return (pointingUp ? from : to);} + }; + + friend class CompareVertices; + class CompareVertices + { + public: + CompareVertices(SimpleToMonotone *parent) : m_parent(parent) { } + bool operator () (int i, int j) const; + private: + SimpleToMonotone *m_parent; + }; + + void setupDataStructures(); + void removeZeroLengthEdges(); + void fillPriorityQueue(); + bool edgeIsLeftOfEdge(int leftEdgeIndex, int rightEdgeIndex) const; + // Returns the rightmost edge not to the right of the given edge. + QRBTree::Node *searchEdgeLeftOfEdge(int edgeIndex) const; + // Returns the rightmost edge left of the given point. + QRBTree::Node *searchEdgeLeftOfPoint(int pointIndex) const; + void classifyVertex(int i); + void classifyVertices(); + bool pointIsInSector(const QPodPoint &p, const QPodPoint &v1, const QPodPoint &v2, const QPodPoint &v3); + bool pointIsInSector(int vertex, int sector); + int findSector(int edge, int vertex); + void createDiagonal(int lower, int upper); + void monotoneDecomposition(); + + QTriangulator *m_parent; + QRBTree m_edgeList; + QDataBuffer m_edges; + QDataBuffer m_upperVertex; + bool m_clockwiseOrder; + }; + + //====================================// + // QTriangulator::MonotoneToTriangles // + //====================================// + friend class MonotoneToTriangles; + class MonotoneToTriangles + { + public: + inline MonotoneToTriangles(QTriangulator *parent) : m_parent(parent) { } + void decompose(); + private: + inline T indices(int index) const {return m_parent->m_indices.at(index + m_first);} + inline int next(int index) const {return (index + 1) % m_length;} + inline int previous(int index) const {return (index + m_length - 1) % m_length;} + inline bool less(int i, int j) const {return m_parent->m_vertices.at((qint32)indices(i)) < m_parent->m_vertices.at(indices(j));} + inline bool leftOfEdge(int i, int j, int k) const + { + return qPointIsLeftOfLine(m_parent->m_vertices.at((qint32)indices(i)), + m_parent->m_vertices.at((qint32)indices(j)), m_parent->m_vertices.at((qint32)indices(k))); + } + + QTriangulator *m_parent; + int m_first; + int m_length; + }; + + inline QTriangulator() : m_vertices(0) { } + + // Call this only once. + void initialize(const qreal *polygon, int count, uint hint, const QTransform &matrix); + // Call this only once. + void initialize(const QVectorPath &path, const QTransform &matrix, qreal lod); + // Call this only once. + void initialize(const QPainterPath &path, const QTransform &matrix, qreal lod); + // Call either triangulate() or polyline() only once. + QVertexSet triangulate(); + QVertexSet polyline(); +private: + QDataBuffer m_vertices; + QVector m_indices; + uint m_hint; +}; + +//============================================================================// +// QTriangulator // +//============================================================================// + +template +QVertexSet QTriangulator::triangulate() +{ + for (int i = 0; i < m_vertices.size(); ++i) { + Q_ASSERT(qAbs(m_vertices.at(i).x) < (1 << 21)); + Q_ASSERT(qAbs(m_vertices.at(i).y) < (1 << 21)); + } + + if (!(m_hint & (QVectorPath::OddEvenFill | QVectorPath::WindingFill))) + m_hint |= QVectorPath::OddEvenFill; + + if (m_hint & QVectorPath::NonConvexShapeMask) { + ComplexToSimple c2s(this); + c2s.decompose(); + SimpleToMonotone s2m(this); + s2m.decompose(); + } + MonotoneToTriangles m2t(this); + m2t.decompose(); + + QVertexSet result; + result.indices = m_indices; + result.vertices.resize(2 * m_vertices.size()); + for (int i = 0; i < m_vertices.size(); ++i) { + result.vertices[2 * i + 0] = qreal(m_vertices.at(i).x) / Q_FIXED_POINT_SCALE; + result.vertices[2 * i + 1] = qreal(m_vertices.at(i).y) / Q_FIXED_POINT_SCALE; + } + return result; +} + +template +QVertexSet QTriangulator::polyline() +{ + for (int i = 0; i < m_vertices.size(); ++i) { + Q_ASSERT(qAbs(m_vertices.at(i).x) < (1 << 21)); + Q_ASSERT(qAbs(m_vertices.at(i).y) < (1 << 21)); + } + + if (!(m_hint & (QVectorPath::OddEvenFill | QVectorPath::WindingFill))) + m_hint |= QVectorPath::OddEvenFill; + + if (m_hint & QVectorPath::NonConvexShapeMask) { + ComplexToSimple c2s(this); + c2s.decompose(); + } + + QVertexSet result; + result.indices = m_indices; + result.vertices.resize(2 * m_vertices.size()); + for (int i = 0; i < m_vertices.size(); ++i) { + result.vertices[2 * i + 0] = qreal(m_vertices.at(i).x) / Q_FIXED_POINT_SCALE; + result.vertices[2 * i + 1] = qreal(m_vertices.at(i).y) / Q_FIXED_POINT_SCALE; + } + return result; +} + +template +void QTriangulator::initialize(const qreal *polygon, int count, uint hint, const QTransform &matrix) +{ + m_hint = hint; + m_vertices.resize(count); + m_indices.resize(count + 1); + for (int i = 0; i < count; ++i) { + qreal x, y; + matrix.map(polygon[2 * i + 0], polygon[2 * i + 1], &x, &y); + m_vertices.at(i).x = qRound(x * Q_FIXED_POINT_SCALE); + m_vertices.at(i).y = qRound(y * Q_FIXED_POINT_SCALE); + m_indices[i] = i; + } + m_indices[count] = T(-1); //Q_TRIANGULATE_END_OF_POLYGON +} + +template +void QTriangulator::initialize(const QVectorPath &path, const QTransform &matrix, qreal lod) +{ + m_hint = path.hints(); + // Curved paths will be converted to complex polygons. + m_hint &= ~QVectorPath::CurvedShapeMask; + + const qreal *p = path.points(); + const QPainterPath::ElementType *e = path.elements(); + if (e) { + for (int i = 0; i < path.elementCount(); ++i, ++e, p += 2) { + switch (*e) { + case QPainterPath::MoveToElement: + if (!m_indices.isEmpty()) + m_indices.push_back(T(-1)); // Q_TRIANGULATE_END_OF_POLYGON + // Fall through. + case QPainterPath::LineToElement: + m_indices.push_back(T(m_vertices.size())); + m_vertices.resize(m_vertices.size() + 1); + qreal x, y; + matrix.map(p[0], p[1], &x, &y); + m_vertices.last().x = qRound(x * Q_FIXED_POINT_SCALE); + m_vertices.last().y = qRound(y * Q_FIXED_POINT_SCALE); + break; + case QPainterPath::CurveToElement: + { + qreal pts[8]; + for (int i = 0; i < 4; ++i) + matrix.map(p[2 * i - 2], p[2 * i - 1], &pts[2 * i + 0], &pts[2 * i + 1]); + for (int i = 0; i < 8; ++i) + pts[i] *= lod; + QBezier bezier = QBezier::fromPoints(QPointF(pts[0], pts[1]), QPointF(pts[2], pts[3]), QPointF(pts[4], pts[5]), QPointF(pts[6], pts[7])); + QPolygonF poly = bezier.toPolygon(); + // Skip first point, it already exists in 'm_vertices'. + for (int j = 1; j < poly.size(); ++j) { + m_indices.push_back(T(m_vertices.size())); + m_vertices.resize(m_vertices.size() + 1); + m_vertices.last().x = qRound(poly.at(j).x() * Q_FIXED_POINT_SCALE / lod); + m_vertices.last().y = qRound(poly.at(j).y() * Q_FIXED_POINT_SCALE / lod); + } + } + i += 2; + e += 2; + p += 4; + break; + default: + Q_ASSERT_X(0, "QTriangulator::triangulate", "Unexpected element type."); + break; + } + } + } else { + for (int i = 0; i < path.elementCount(); ++i, p += 2) { + m_indices.push_back(T(m_vertices.size())); + m_vertices.resize(m_vertices.size() + 1); + qreal x, y; + matrix.map(p[0], p[1], &x, &y); + m_vertices.last().x = qRound(x * Q_FIXED_POINT_SCALE); + m_vertices.last().y = qRound(y * Q_FIXED_POINT_SCALE); + } + } + m_indices.push_back(T(-1)); // Q_TRIANGULATE_END_OF_POLYGON +} + +template +void QTriangulator::initialize(const QPainterPath &path, const QTransform &matrix, qreal lod) +{ + initialize(qtVectorPathForPath(path), matrix, lod); +} + +//============================================================================// +// QTriangulator::ComplexToSimple // +//============================================================================// +template +void QTriangulator::ComplexToSimple::decompose() +{ + m_initialPointCount = m_parent->m_vertices.size(); + initEdges(); + do { + calculateIntersections(); + } while (splitEdgesAtIntersections()); + + removeUnwantedEdgesAndConnect(); + removeUnusedPoints(); + + m_parent->m_indices.clear(); + QBitArray processed(m_edges.size(), false); + for (int first = 0; first < m_edges.size(); ++first) { + // If already processed, or if unused path, skip. + if (processed.at(first) || m_edges.at(first).next == -1) + continue; + + int i = first; + do { + Q_ASSERT(!processed.at(i)); + Q_ASSERT(m_edges.at(m_edges.at(i).next).previous == i); + m_parent->m_indices.push_back(m_edges.at(i).from); + processed.setBit(i); + i = m_edges.at(i).next; // CCW order + } while (i != first); + m_parent->m_indices.push_back(T(-1)); // Q_TRIANGULATE_END_OF_POLYGON + } +} + +template +void QTriangulator::ComplexToSimple::initEdges() +{ + // Initialize edge structure. + // 'next' and 'previous' are not being initialized at this point. + int first = 0; + for (int i = 0; i < m_parent->m_indices.size(); ++i) { + if (m_parent->m_indices.at(i) == T(-1)) { // Q_TRIANGULATE_END_OF_POLYGON + if (m_edges.size() != first) + m_edges.last().to = m_edges.at(first).from; + first = m_edges.size(); + } else { + Q_ASSERT(i + 1 < m_parent->m_indices.size()); + // {node, from, to, next, previous, winding, mayIntersect, pointingUp, originallyPointingUp} + Edge edge = {0, m_parent->m_indices.at(i), m_parent->m_indices.at(i + 1), -1, -1, 0, true, false, false}; + m_edges.add(edge); + } + } + if (first != m_edges.size()) + m_edges.last().to = m_edges.at(first).from; + for (int i = 0; i < m_edges.size(); ++i) { + m_edges.at(i).originallyPointingUp = m_edges.at(i).pointingUp = + m_parent->m_vertices.at(m_edges.at(i).to) < m_parent->m_vertices.at(m_edges.at(i).from); + } +} + +// Return true if new intersection was found +template +bool QTriangulator::ComplexToSimple::calculateIntersection(int left, int right) +{ + const Edge &e1 = m_edges.at(left); + const Edge &e2 = m_edges.at(right); + + const QPodPoint &u1 = m_parent->m_vertices.at((qint32)e1.from); + const QPodPoint &u2 = m_parent->m_vertices.at((qint32)e1.to); + const QPodPoint &v1 = m_parent->m_vertices.at((qint32)e2.from); + const QPodPoint &v2 = m_parent->m_vertices.at((qint32)e2.to); + if (qMax(u1.x, u2.x) <= qMin(v1.x, v2.x)) + return false; + + quint64 key = (left > right ? (quint64(right) << 32) | quint64(left) : (quint64(left) << 32) | quint64(right)); + if (m_processedEdgePairs.contains(key)) + return false; + m_processedEdgePairs.insert(key); + + Intersection intersection; + intersection.leftEdge = left; + intersection.rightEdge = right; + intersection.intersectionPoint = QT_PREPEND_NAMESPACE(qIntersectionPoint)(u1, u2, v1, v2); + + if (!intersection.intersectionPoint.isValid()) + return false; + + Q_ASSERT(intersection.intersectionPoint.isOnLine(u1, u2)); + Q_ASSERT(intersection.intersectionPoint.isOnLine(v1, v2)); + + intersection.vertex = m_parent->m_vertices.size(); + m_topIntersection.push(intersection); + m_parent->m_vertices.add(intersection.intersectionPoint.round()); + return true; +} + +template +bool QTriangulator::ComplexToSimple::edgeIsLeftOfEdge(int leftEdgeIndex, int rightEdgeIndex) const +{ + const Edge &leftEdge = m_edges.at(leftEdgeIndex); + const Edge &rightEdge = m_edges.at(rightEdgeIndex); + const QPodPoint &u = m_parent->m_vertices.at(rightEdge.upper()); + const QPodPoint &l = m_parent->m_vertices.at(rightEdge.lower()); + const QPodPoint &upper = m_parent->m_vertices.at(leftEdge.upper()); + if (upper.x < qMin(l.x, u.x)) + return true; + if (upper.x > qMax(l.x, u.x)) + return false; + qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(upper, l, u); + // d < 0: left, d > 0: right, d == 0: on top + if (d == 0) + d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(m_parent->m_vertices.at(leftEdge.lower()), l, u); + return d < 0; +} + +template +QRBTree::Node *QTriangulator::ComplexToSimple::searchEdgeLeftOf(int edgeIndex) const +{ + QRBTree::Node *current = m_edgeList.root; + QRBTree::Node *result = 0; + while (current) { + if (edgeIsLeftOfEdge(edgeIndex, current->data)) { + current = current->left; + } else { + result = current; + current = current->right; + } + } + return result; +} + +template +QRBTree::Node *QTriangulator::ComplexToSimple::searchEdgeLeftOf(int edgeIndex, QRBTree::Node *after) const +{ + if (!m_edgeList.root) + return after; + QRBTree::Node *result = after; + QRBTree::Node *current = (after ? m_edgeList.next(after) : m_edgeList.front(m_edgeList.root)); + while (current) { + if (edgeIsLeftOfEdge(edgeIndex, current->data)) + return result; + result = current; + current = m_edgeList.next(current); + } + return result; +} + +template +QPair::Node *, QRBTree::Node *> QTriangulator::ComplexToSimple::bounds(const QPodPoint &point) const +{ + QRBTree::Node *current = m_edgeList.root; + QPair::Node *, QRBTree::Node *> result(0, 0); + while (current) { + const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower()); + const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper()); + qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2); + if (d == 0) { + result.first = result.second = current; + break; + } + current = (d < 0 ? current->left : current->right); + } + if (current == 0) + return result; + + current = result.first->left; + while (current) { + const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower()); + const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper()); + qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2); + Q_ASSERT(d >= 0); + if (d == 0) { + result.first = current; + current = current->left; + } else { + current = current->right; + } + } + + current = result.second->right; + while (current) { + const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower()); + const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper()); + qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2); + Q_ASSERT(d <= 0); + if (d == 0) { + result.second = current; + current = current->right; + } else { + current = current->left; + } + } + + return result; +} + +template +QPair::Node *, QRBTree::Node *> QTriangulator::ComplexToSimple::outerBounds(const QPodPoint &point) const +{ + QRBTree::Node *current = m_edgeList.root; + QPair::Node *, QRBTree::Node *> result(0, 0); + + while (current) { + const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower()); + const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper()); + qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2); + if (d == 0) + break; + if (d < 0) { + result.second = current; + current = current->left; + } else { + result.first = current; + current = current->right; + } + } + + if (!current) + return result; + + QRBTree::Node *mid = current; + + current = mid->left; + while (current) { + const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower()); + const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper()); + qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2); + Q_ASSERT(d >= 0); + if (d == 0) { + current = current->left; + } else { + result.first = current; + current = current->right; + } + } + + current = mid->right; + while (current) { + const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(current->data).lower()); + const QPodPoint &v2 = m_parent->m_vertices.at(m_edges.at(current->data).upper()); + qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(point, v1, v2); + Q_ASSERT(d <= 0); + if (d == 0) { + current = current->right; + } else { + result.second = current; + current = current->left; + } + } + + return result; +} + +template +void QTriangulator::ComplexToSimple::splitEdgeListRange(QRBTree::Node *leftmost, QRBTree::Node *rightmost, int vertex, const QIntersectionPoint &intersectionPoint) +{ + Q_ASSERT(leftmost && rightmost); + + // Split. + for (;;) { + const QPodPoint &u = m_parent->m_vertices.at(m_edges.at(leftmost->data).from); + const QPodPoint &v = m_parent->m_vertices.at(m_edges.at(leftmost->data).to); + Q_ASSERT(intersectionPoint.isOnLine(u, v)); + const Split split = {vertex, leftmost->data, intersectionPoint.isAccurate()}; + if (intersectionPoint.xOffset.numerator != 0 || intersectionPoint.yOffset.numerator != 0 || (intersectionPoint.upperLeft != u && intersectionPoint.upperLeft != v)) + m_splits.add(split); + if (leftmost == rightmost) + break; + leftmost = m_edgeList.next(leftmost); + } +} + +template +void QTriangulator::ComplexToSimple::reorderEdgeListRange(QRBTree::Node *leftmost, QRBTree::Node *rightmost) +{ + Q_ASSERT(leftmost && rightmost); + + QRBTree::Node *storeLeftmost = leftmost; + QRBTree::Node *storeRightmost = rightmost; + + // Reorder. + while (leftmost != rightmost) { + Edge &left = m_edges.at(leftmost->data); + Edge &right = m_edges.at(rightmost->data); + qSwap(left.node, right.node); + qSwap(leftmost->data, rightmost->data); + leftmost = m_edgeList.next(leftmost); + if (leftmost == rightmost) + break; + rightmost = m_edgeList.previous(rightmost); + } + + rightmost = m_edgeList.next(storeRightmost); + leftmost = m_edgeList.previous(storeLeftmost); + if (leftmost) + calculateIntersection(leftmost->data, storeLeftmost->data); + if (rightmost) + calculateIntersection(storeRightmost->data, rightmost->data); +} + +template +void QTriangulator::ComplexToSimple::sortEdgeList(const QPodPoint eventPoint) +{ + QIntersectionPoint eventPoint2 = QT_PREPEND_NAMESPACE(qIntersectionPoint)(eventPoint); + while (!m_topIntersection.isEmpty() && m_topIntersection.top().intersectionPoint < eventPoint2) { + Intersection intersection = m_topIntersection.pop(); + + QIntersectionPoint currentIntersectionPoint = intersection.intersectionPoint; + int currentVertex = intersection.vertex; + + QRBTree::Node *leftmost = m_edges.at(intersection.leftEdge).node; + QRBTree::Node *rightmost = m_edges.at(intersection.rightEdge).node; + + for (;;) { + QRBTree::Node *previous = m_edgeList.previous(leftmost); + if (!previous) + break; + const Edge &edge = m_edges.at(previous->data); + const QPodPoint &u = m_parent->m_vertices.at((qint32)edge.from); + const QPodPoint &v = m_parent->m_vertices.at((qint32)edge.to); + if (!currentIntersectionPoint.isOnLine(u, v)) { + Q_ASSERT(!currentIntersectionPoint.isAccurate() || qCross(currentIntersectionPoint.upperLeft - u, v - u) != 0); + break; + } + leftmost = previous; + } + + for (;;) { + QRBTree::Node *next = m_edgeList.next(rightmost); + if (!next) + break; + const Edge &edge = m_edges.at(next->data); + const QPodPoint &u = m_parent->m_vertices.at((qint32)edge.from); + const QPodPoint &v = m_parent->m_vertices.at((qint32)edge.to); + if (!currentIntersectionPoint.isOnLine(u, v)) { + Q_ASSERT(!currentIntersectionPoint.isAccurate() || qCross(currentIntersectionPoint.upperLeft - u, v - u) != 0); + break; + } + rightmost = next; + } + + Q_ASSERT(leftmost && rightmost); + splitEdgeListRange(leftmost, rightmost, currentVertex, currentIntersectionPoint); + reorderEdgeListRange(leftmost, rightmost); + + while (!m_topIntersection.isEmpty() && m_topIntersection.top().intersectionPoint <= currentIntersectionPoint) + m_topIntersection.pop(); + +#ifdef Q_TRIANGULATOR_DEBUG + DebugDialog dialog(this, intersection.vertex); + dialog.exec(); +#endif + + } +} + +template +void QTriangulator::ComplexToSimple::fillPriorityQueue() +{ + m_events.reset(); + m_events.reserve(m_edges.size() * 2); + for (int i = 0; i < m_edges.size(); ++i) { + Q_ASSERT(m_edges.at(i).previous == -1 && m_edges.at(i).next == -1); + Q_ASSERT(m_edges.at(i).node == 0); + Q_ASSERT(m_edges.at(i).pointingUp == m_edges.at(i).originallyPointingUp); + Q_ASSERT(m_edges.at(i).pointingUp == (m_parent->m_vertices.at(m_edges.at(i).to) < m_parent->m_vertices.at(m_edges.at(i).from))); + // Ignore zero-length edges. + if (m_parent->m_vertices.at(m_edges.at(i).to) != m_parent->m_vertices.at(m_edges.at(i).from)) { + QPodPoint upper = m_parent->m_vertices.at(m_edges.at(i).upper()); + QPodPoint lower = m_parent->m_vertices.at(m_edges.at(i).lower()); + Event upperEvent = {{upper.x, upper.y}, Event::Upper, i}; + Event lowerEvent = {{lower.x, lower.y}, Event::Lower, i}; + m_events.add(upperEvent); + m_events.add(lowerEvent); + } + } + //qSort(m_events.data(), m_events.data() + m_events.size()); + sort(m_events.data(), m_events.size()); +} + +template +void QTriangulator::ComplexToSimple::calculateIntersections() +{ + fillPriorityQueue(); + + Q_ASSERT(m_topIntersection.empty()); + Q_ASSERT(m_edgeList.root == 0); + + // Find all intersection points. + while (!m_events.isEmpty()) { + Event event = m_events.last(); + sortEdgeList(event.point); + + // Find all edges in the edge list that contain the current vertex and mark them to be split later. + QPair::Node *, QRBTree::Node *> range = bounds(event.point); + QRBTree::Node *leftNode = range.first ? m_edgeList.previous(range.first) : 0; + int vertex = (event.type == Event::Upper ? m_edges.at(event.edge).upper() : m_edges.at(event.edge).lower()); + QIntersectionPoint eventPoint = QT_PREPEND_NAMESPACE(qIntersectionPoint)(event.point); + + if (range.first != 0) { + splitEdgeListRange(range.first, range.second, vertex, eventPoint); + reorderEdgeListRange(range.first, range.second); + } + + // Handle the edges with start or end point in the current vertex. + while (!m_events.isEmpty() && m_events.last().point == event.point) { + event = m_events.last(); + m_events.pop_back(); + int i = event.edge; + + if (m_edges.at(i).node) { + // Remove edge from edge list. + Q_ASSERT(event.type == Event::Lower); + QRBTree::Node *left = m_edgeList.previous(m_edges.at(i).node); + QRBTree::Node *right = m_edgeList.next(m_edges.at(i).node); + m_edgeList.deleteNode(m_edges.at(i).node); + if (!left || !right) + continue; + calculateIntersection(left->data, right->data); + } else { + // Insert edge into edge list. + Q_ASSERT(event.type == Event::Upper); + QRBTree::Node *left = searchEdgeLeftOf(i, leftNode); + m_edgeList.attachAfter(left, m_edges.at(i).node = m_edgeList.newNode()); + m_edges.at(i).node->data = i; + QRBTree::Node *right = m_edgeList.next(m_edges.at(i).node); + if (left) + calculateIntersection(left->data, i); + if (right) + calculateIntersection(i, right->data); + } + } + while (!m_topIntersection.isEmpty() && m_topIntersection.top().intersectionPoint <= eventPoint) + m_topIntersection.pop(); +#ifdef Q_TRIANGULATOR_DEBUG + DebugDialog dialog(this, vertex); + dialog.exec(); +#endif + } + m_processedEdgePairs.clear(); +} + +// Split an edge into two pieces at the given point. +// The upper piece is pushed to the end of the 'm_edges' vector. +// The lower piece replaces the old edge. +// Return the edge whose 'from' is 'pointIndex'. +template +int QTriangulator::ComplexToSimple::splitEdge(int splitIndex) +{ + const Split &split = m_splits.at(splitIndex); + Edge &lowerEdge = m_edges.at(split.edge); + Q_ASSERT(lowerEdge.node == 0); + Q_ASSERT(lowerEdge.previous == -1 && lowerEdge.next == -1); + + if (lowerEdge.from == split.vertex) + return split.edge; + if (lowerEdge.to == split.vertex) + return lowerEdge.next; + + // Check that angle >= 90 degrees. + //Q_ASSERT(qDot(m_points.at(m_edges.at(edgeIndex).from) - m_points.at(pointIndex), + // m_points.at(m_edges.at(edgeIndex).to) - m_points.at(pointIndex)) <= 0); + + Edge upperEdge = lowerEdge; + upperEdge.mayIntersect |= !split.accurate; // The edge may have been split before at an inaccurate split point. + lowerEdge.mayIntersect = !split.accurate; + if (lowerEdge.pointingUp) { + lowerEdge.to = upperEdge.from = split.vertex; + m_edges.add(upperEdge); + return m_edges.size() - 1; + } else { + lowerEdge.from = upperEdge.to = split.vertex; + m_edges.add(upperEdge); + return split.edge; + } +} + +template +bool QTriangulator::ComplexToSimple::splitEdgesAtIntersections() +{ + for (int i = 0; i < m_edges.size(); ++i) + m_edges.at(i).mayIntersect = false; + bool checkForNewIntersections = false; + for (int i = 0; i < m_splits.size(); ++i) { + splitEdge(i); + checkForNewIntersections |= !m_splits.at(i).accurate; + } + for (int i = 0; i < m_edges.size(); ++i) { + m_edges.at(i).originallyPointingUp = m_edges.at(i).pointingUp = + m_parent->m_vertices.at(m_edges.at(i).to) < m_parent->m_vertices.at(m_edges.at(i).from); + } + m_splits.reset(); + return checkForNewIntersections; +} + +template +void QTriangulator::ComplexToSimple::insertEdgeIntoVectorIfWanted(ShortArray &orderedEdges, int i) +{ + // Edges with zero length should not reach this part. + Q_ASSERT(m_parent->m_vertices.at(m_edges.at(i).from) != m_parent->m_vertices.at(m_edges.at(i).to)); + + // Skip edges with unwanted winding number. + int windingNumber = m_edges.at(i).winding; + if (m_edges.at(i).originallyPointingUp) + ++windingNumber; + + // Make sure exactly one fill rule is specified. + Q_ASSERT(((m_parent->m_hint & QVectorPath::WindingFill) != 0) != ((m_parent->m_hint & QVectorPath::OddEvenFill) != 0)); + + if ((m_parent->m_hint & QVectorPath::WindingFill) && windingNumber != 0 && windingNumber != 1) + return; + + // Skip cancelling edges. + if (!orderedEdges.isEmpty()) { + int j = orderedEdges[orderedEdges.size() - 1]; + // If the last edge is already connected in one end, it should not be cancelled. + if (m_edges.at(j).next == -1 && m_edges.at(j).previous == -1 + && (m_parent->m_vertices.at(m_edges.at(i).from) == m_parent->m_vertices.at(m_edges.at(j).to)) + && (m_parent->m_vertices.at(m_edges.at(i).to) == m_parent->m_vertices.at(m_edges.at(j).from))) { + orderedEdges.removeLast(); + return; + } + } + orderedEdges.append(i); +} + +template +void QTriangulator::ComplexToSimple::removeUnwantedEdgesAndConnect() +{ + Q_ASSERT(m_edgeList.root == 0); + // Initialize priority queue. + fillPriorityQueue(); + + ShortArray orderedEdges; + + while (!m_events.isEmpty()) { + Event event = m_events.last(); + int edgeIndex = event.edge; + + // Check that all the edges in the list crosses the current scanline + //if (m_edgeList.root) { + // for (QRBTree::Node *node = m_edgeList.front(m_edgeList.root); node; node = m_edgeList.next(node)) { + // Q_ASSERT(event.point <= m_points.at(m_edges.at(node->data).lower())); + // } + //} + + orderedEdges.clear(); + QPair::Node *, QRBTree::Node *> b = outerBounds(event.point); + if (m_edgeList.root) { + QRBTree::Node *current = (b.first ? m_edgeList.next(b.first) : m_edgeList.front(m_edgeList.root)); + // Process edges that are going to be removed from the edge list at the current event point. + while (current != b.second) { + Q_ASSERT(current); + Q_ASSERT(m_edges.at(current->data).node == current); + Q_ASSERT(QT_PREPEND_NAMESPACE(qIntersectionPoint)(event.point).isOnLine(m_parent->m_vertices.at(m_edges.at(current->data).from), m_parent->m_vertices.at(m_edges.at(current->data).to))); + Q_ASSERT(m_parent->m_vertices.at(m_edges.at(current->data).from) == event.point || m_parent->m_vertices.at(m_edges.at(current->data).to) == event.point); + insertEdgeIntoVectorIfWanted(orderedEdges, current->data); + current = m_edgeList.next(current); + } + } + + // Remove edges above the event point, insert edges below the event point. + do { + event = m_events.last(); + m_events.pop_back(); + edgeIndex = event.edge; + + // Edges with zero length should not reach this part. + Q_ASSERT(m_parent->m_vertices.at(m_edges.at(edgeIndex).from) != m_parent->m_vertices.at(m_edges.at(edgeIndex).to)); + + if (m_edges.at(edgeIndex).node) { + Q_ASSERT(event.type == Event::Lower); + Q_ASSERT(event.point == m_parent->m_vertices.at(m_edges.at(event.edge).lower())); + m_edgeList.deleteNode(m_edges.at(edgeIndex).node); + } else { + Q_ASSERT(event.type == Event::Upper); + Q_ASSERT(event.point == m_parent->m_vertices.at(m_edges.at(event.edge).upper())); + QRBTree::Node *left = searchEdgeLeftOf(edgeIndex, b.first); + m_edgeList.attachAfter(left, m_edges.at(edgeIndex).node = m_edgeList.newNode()); + m_edges.at(edgeIndex).node->data = edgeIndex; + } + } while (!m_events.isEmpty() && m_events.last().point == event.point); + + if (m_edgeList.root) { + QRBTree::Node *current = (b.first ? m_edgeList.next(b.first) : m_edgeList.front(m_edgeList.root)); + + // Calculate winding number and turn counter-clockwise. + int currentWindingNumber = (b.first ? m_edges.at(b.first->data).winding : 0); + while (current != b.second) { + Q_ASSERT(current); + //Q_ASSERT(b.second == 0 || m_edgeList.order(current, b.second) < 0); + int i = current->data; + Q_ASSERT(m_edges.at(i).node == current); + + // Winding number. + int ccwWindingNumber = m_edges.at(i).winding = currentWindingNumber; + if (m_edges.at(i).originallyPointingUp) { + --m_edges.at(i).winding; + } else { + ++m_edges.at(i).winding; + ++ccwWindingNumber; + } + currentWindingNumber = m_edges.at(i).winding; + + // Turn counter-clockwise. + if ((ccwWindingNumber & 1) == 0) { + Q_ASSERT(m_edges.at(i).previous == -1 && m_edges.at(i).next == -1); + qSwap(m_edges.at(i).from, m_edges.at(i).to); + m_edges.at(i).pointingUp = !m_edges.at(i).pointingUp; + } + + current = m_edgeList.next(current); + } + + // Process edges that were inserted into the edge list at the current event point. + current = (b.second ? m_edgeList.previous(b.second) : m_edgeList.back(m_edgeList.root)); + while (current != b.first) { + Q_ASSERT(current); + Q_ASSERT(m_edges.at(current->data).node == current); + insertEdgeIntoVectorIfWanted(orderedEdges, current->data); + current = m_edgeList.previous(current); + } + } + if (orderedEdges.isEmpty()) + continue; + + Q_ASSERT((orderedEdges.size() & 1) == 0); + + // Connect edges. + // First make sure the first edge point towards the current point. + int i; + if (m_parent->m_vertices.at(m_edges.at(orderedEdges[0]).from) == event.point) { + i = 1; + int copy = orderedEdges[0]; // Make copy in case the append() will cause a reallocation. + orderedEdges.append(copy); + } else { + Q_ASSERT(m_parent->m_vertices.at(m_edges.at(orderedEdges[0]).to) == event.point); + i = 0; + } + + // Remove references to duplicate points. First find the point with lowest index. + int pointIndex = INT_MAX; + for (int j = i; j < orderedEdges.size(); j += 2) { + Q_ASSERT(j + 1 < orderedEdges.size()); + Q_ASSERT(m_parent->m_vertices.at(m_edges.at(orderedEdges[j]).to) == event.point); + Q_ASSERT(m_parent->m_vertices.at(m_edges.at(orderedEdges[j + 1]).from) == event.point); + if (m_edges.at(orderedEdges[j]).to < pointIndex) + pointIndex = m_edges.at(orderedEdges[j]).to; + if (m_edges.at(orderedEdges[j + 1]).from < pointIndex) + pointIndex = m_edges.at(orderedEdges[j + 1]).from; + } + + for (; i < orderedEdges.size(); i += 2) { + // Remove references to duplicate points by making all edges reference one common point. + m_edges.at(orderedEdges[i]).to = m_edges.at(orderedEdges[i + 1]).from = pointIndex; + + Q_ASSERT(m_edges.at(orderedEdges[i]).pointingUp || m_edges.at(orderedEdges[i]).previous != -1); + Q_ASSERT(!m_edges.at(orderedEdges[i + 1]).pointingUp || m_edges.at(orderedEdges[i + 1]).next != -1); + + m_edges.at(orderedEdges[i]).next = orderedEdges[i + 1]; + m_edges.at(orderedEdges[i + 1]).previous = orderedEdges[i]; + } + } // end while +} + +template +void QTriangulator::ComplexToSimple::removeUnusedPoints() { + QBitArray used(m_parent->m_vertices.size(), false); + for (int i = 0; i < m_edges.size(); ++i) { + Q_ASSERT((m_edges.at(i).previous == -1) == (m_edges.at(i).next == -1)); + if (m_edges.at(i).next != -1) + used.setBit(m_edges.at(i).from); + } + QDataBuffer newMapping(m_parent->m_vertices.size()); + newMapping.resize(m_parent->m_vertices.size()); + int count = 0; + for (int i = 0; i < m_parent->m_vertices.size(); ++i) { + if (used.at(i)) { + m_parent->m_vertices.at(count) = m_parent->m_vertices.at(i); + newMapping.at(i) = count; + ++count; + } + } + m_parent->m_vertices.resize(count); + for (int i = 0; i < m_edges.size(); ++i) { + m_edges.at(i).from = newMapping.at(m_edges.at(i).from); + m_edges.at(i).to = newMapping.at(m_edges.at(i).to); + } +} + +template +bool QTriangulator::ComplexToSimple::CompareEdges::operator () (int i, int j) const +{ + int cmp = comparePoints(m_parent->m_parent->m_vertices.at(m_parent->m_edges.at(i).from), + m_parent->m_parent->m_vertices.at(m_parent->m_edges.at(j).from)); + if (cmp == 0) { + cmp = comparePoints(m_parent->m_parent->m_vertices.at(m_parent->m_edges.at(i).to), + m_parent->m_parent->m_vertices.at(m_parent->m_edges.at(j).to)); + } + return cmp > 0; +} + +template +inline bool QTriangulator::ComplexToSimple::Event::operator < (const Event &other) const +{ + if (point == other.point) + return type < other.type; // 'Lower' has higher priority than 'Upper'. + return other.point < point; +} + +//============================================================================// +// QTriangulator::ComplexToSimple::DebugDialog // +//============================================================================// + +#ifdef Q_TRIANGULATOR_DEBUG +template +QTriangulator::ComplexToSimple::DebugDialog::DebugDialog(ComplexToSimple *parent, int currentVertex) + : m_parent(parent), m_vertex(currentVertex) +{ + QDataBuffer &vertices = m_parent->m_parent->m_vertices; + if (vertices.isEmpty()) + return; + + int minX, maxX, minY, maxY; + minX = maxX = vertices.at(0).x; + minY = maxY = vertices.at(0).y; + for (int i = 1; i < vertices.size(); ++i) { + minX = qMin(minX, vertices.at(i).x); + maxX = qMax(maxX, vertices.at(i).x); + minY = qMin(minY, vertices.at(i).y); + maxY = qMax(maxY, vertices.at(i).y); + } + int w = maxX - minX; + int h = maxY - minY; + qreal border = qMin(w, h) / 10.0; + m_window = QRectF(minX - border, minY - border, (maxX - minX + 2 * border), (maxY - minY + 2 * border)); +} + +template +void QTriangulator::ComplexToSimple::DebugDialog::paintEvent(QPaintEvent *) +{ + QPainter p(this); + p.setRenderHint(QPainter::Antialiasing, true); + p.fillRect(rect(), Qt::black); + QDataBuffer &vertices = m_parent->m_parent->m_vertices; + if (vertices.isEmpty()) + return; + + qreal halfPointSize = qMin(m_window.width(), m_window.height()) / 300.0; + p.setWindow(m_window.toRect()); + + p.setPen(Qt::white); + + QDataBuffer &edges = m_parent->m_edges; + for (int i = 0; i < edges.size(); ++i) { + QPodPoint u = vertices.at(edges.at(i).from); + QPodPoint v = vertices.at(edges.at(i).to); + p.drawLine(u.x, u.y, v.x, v.y); + } + + for (int i = 0; i < vertices.size(); ++i) { + QPodPoint q = vertices.at(i); + p.fillRect(QRectF(q.x - halfPointSize, q.y - halfPointSize, 2 * halfPointSize, 2 * halfPointSize), Qt::red); + } + + Qt::GlobalColor colors[6] = {Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::yellow}; + p.setOpacity(0.5); + int count = 0; + if (m_parent->m_edgeList.root) { + QRBTree::Node *current = m_parent->m_edgeList.front(m_parent->m_edgeList.root); + while (current) { + p.setPen(colors[count++ % 6]); + QPodPoint u = vertices.at(edges.at(current->data).from); + QPodPoint v = vertices.at(edges.at(current->data).to); + p.drawLine(u.x, u.y, v.x, v.y); + current = m_parent->m_edgeList.next(current); + } + } + + p.setOpacity(1.0); + QPodPoint q = vertices.at(m_vertex); + p.fillRect(QRectF(q.x - halfPointSize, q.y - halfPointSize, 2 * halfPointSize, 2 * halfPointSize), Qt::green); + + p.setPen(Qt::gray); + QDataBuffer &splits = m_parent->m_splits; + for (int i = 0; i < splits.size(); ++i) { + QPodPoint q = vertices.at(splits.at(i).vertex); + QPodPoint u = vertices.at(edges.at(splits.at(i).edge).from) - q; + QPodPoint v = vertices.at(edges.at(splits.at(i).edge).to) - q; + qreal uLen = sqrt(qreal(qDot(u, u))); + qreal vLen = sqrt(qreal(qDot(v, v))); + if (uLen) { + u.x *= 2 * halfPointSize / uLen; + u.y *= 2 * halfPointSize / uLen; + } + if (vLen) { + v.x *= 2 * halfPointSize / vLen; + v.y *= 2 * halfPointSize / vLen; + } + u += q; + v += q; + p.drawLine(u.x, u.y, v.x, v.y); + } +} + +template +void QTriangulator::ComplexToSimple::DebugDialog::wheelEvent(QWheelEvent *event) +{ + qreal scale = exp(-0.001 * event->delta()); + QPointF center = m_window.center(); + QPointF delta = scale * (m_window.bottomRight() - center); + m_window = QRectF(center - delta, center + delta); + event->accept(); + update(); +} + +template +void QTriangulator::ComplexToSimple::DebugDialog::mouseMoveEvent(QMouseEvent *event) +{ + if (event->buttons() & Qt::LeftButton) { + QPointF delta = event->pos() - m_lastMousePos; + delta.setX(delta.x() * m_window.width() / width()); + delta.setY(delta.y() * m_window.height() / height()); + m_window.translate(-delta.x(), -delta.y()); + m_lastMousePos = event->pos(); + event->accept(); + update(); + } +} + +template +void QTriangulator::ComplexToSimple::DebugDialog::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + m_lastMousePos = event->pos(); + event->accept(); +} + + +#endif + +//============================================================================// +// QTriangulator::SimpleToMonotone // +//============================================================================// +template +void QTriangulator::SimpleToMonotone::decompose() +{ + setupDataStructures(); + removeZeroLengthEdges(); + monotoneDecomposition(); + + m_parent->m_indices.clear(); + QBitArray processed(m_edges.size(), false); + for (int first = 0; first < m_edges.size(); ++first) { + if (processed.at(first)) + continue; + int i = first; + do { + Q_ASSERT(!processed.at(i)); + Q_ASSERT(m_edges.at(m_edges.at(i).next).previous == i); + m_parent->m_indices.push_back(m_edges.at(i).from); + processed.setBit(i); + i = m_edges.at(i).next; + } while (i != first); + if (m_parent->m_indices.size() > 0 && m_parent->m_indices.back() != T(-1)) // Q_TRIANGULATE_END_OF_POLYGON + m_parent->m_indices.push_back(T(-1)); // Q_TRIANGULATE_END_OF_POLYGON + } +} + +template +void QTriangulator::SimpleToMonotone::setupDataStructures() +{ + int i = 0; + Edge e; + e.node = 0; + e.twin = -1; + + while (i + 3 <= m_parent->m_indices.size()) { + int start = m_edges.size(); + + do { + e.from = m_parent->m_indices.at(i); + e.type = RegularVertex; + e.next = m_edges.size() + 1; + e.previous = m_edges.size() - 1; + m_edges.add(e); + ++i; + Q_ASSERT(i < m_parent->m_indices.size()); + } while (m_parent->m_indices.at(i) != T(-1)); // Q_TRIANGULATE_END_OF_POLYGON + + m_edges.last().next = start; + m_edges.at(start).previous = m_edges.size() - 1; + ++i; // Skip Q_TRIANGULATE_END_OF_POLYGON. + } + + for (i = 0; i < m_edges.size(); ++i) { + m_edges.at(i).to = m_edges.at(m_edges.at(i).next).from; + m_edges.at(i).pointingUp = m_parent->m_vertices.at(m_edges.at(i).to) < m_parent->m_vertices.at(m_edges.at(i).from); + m_edges.at(i).helper = -1; // Not initialized here. + } +} + +template +void QTriangulator::SimpleToMonotone::removeZeroLengthEdges() +{ + for (int i = 0; i < m_edges.size(); ++i) { + if (m_parent->m_vertices.at(m_edges.at(i).from) == m_parent->m_vertices.at(m_edges.at(i).to)) { + m_edges.at(m_edges.at(i).previous).next = m_edges.at(i).next; + m_edges.at(m_edges.at(i).next).previous = m_edges.at(i).previous; + m_edges.at(m_edges.at(i).next).from = m_edges.at(i).from; + m_edges.at(i).next = -1; // Mark as removed. + } + } + + QDataBuffer newMapping(m_edges.size()); + newMapping.resize(m_edges.size()); + int count = 0; + for (int i = 0; i < m_edges.size(); ++i) { + if (m_edges.at(i).next != -1) { + m_edges.at(count) = m_edges.at(i); + newMapping.at(i) = count; + ++count; + } + } + m_edges.resize(count); + for (int i = 0; i < m_edges.size(); ++i) { + m_edges.at(i).next = newMapping.at(m_edges.at(i).next); + m_edges.at(i).previous = newMapping.at(m_edges.at(i).previous); + } +} + +template +void QTriangulator::SimpleToMonotone::fillPriorityQueue() +{ + m_upperVertex.reset(); + m_upperVertex.reserve(m_edges.size()); + for (int i = 0; i < m_edges.size(); ++i) + m_upperVertex.add(i); + CompareVertices cmp(this); + //qSort(m_upperVertex.data(), m_upperVertex.data() + m_upperVertex.size(), cmp); + sort(m_upperVertex.data(), m_upperVertex.size(), cmp); + //for (int i = 1; i < m_upperVertex.size(); ++i) { + // Q_ASSERT(!cmp(m_upperVertex.at(i), m_upperVertex.at(i - 1))); + //} +} + +template +bool QTriangulator::SimpleToMonotone::edgeIsLeftOfEdge(int leftEdgeIndex, int rightEdgeIndex) const +{ + const Edge &leftEdge = m_edges.at(leftEdgeIndex); + const Edge &rightEdge = m_edges.at(rightEdgeIndex); + const QPodPoint &u = m_parent->m_vertices.at(rightEdge.upper()); + const QPodPoint &l = m_parent->m_vertices.at(rightEdge.lower()); + qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(m_parent->m_vertices.at(leftEdge.upper()), l, u); + // d < 0: left, d > 0: right, d == 0: on top + if (d == 0) + d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(m_parent->m_vertices.at(leftEdge.lower()), l, u); + return d < 0; +} + +// Returns the rightmost edge not to the right of the given edge. +template +QRBTree::Node *QTriangulator::SimpleToMonotone::searchEdgeLeftOfEdge(int edgeIndex) const +{ + QRBTree::Node *current = m_edgeList.root; + QRBTree::Node *result = 0; + while (current) { + if (edgeIsLeftOfEdge(edgeIndex, current->data)) { + current = current->left; + } else { + result = current; + current = current->right; + } + } + return result; +} + +// Returns the rightmost edge left of the given point. +template +QRBTree::Node *QTriangulator::SimpleToMonotone::searchEdgeLeftOfPoint(int pointIndex) const +{ + QRBTree::Node *current = m_edgeList.root; + QRBTree::Node *result = 0; + while (current) { + const QPodPoint &p1 = m_parent->m_vertices.at(m_edges.at(current->data).lower()); + const QPodPoint &p2 = m_parent->m_vertices.at(m_edges.at(current->data).upper()); + qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(m_parent->m_vertices.at(pointIndex), p1, p2); + if (d <= 0) { + current = current->left; + } else { + result = current; + current = current->right; + } + } + return result; +} + +template +void QTriangulator::SimpleToMonotone::classifyVertex(int i) +{ + Edge &e2 = m_edges.at(i); + const Edge &e1 = m_edges.at(e2.previous); + + bool startOrSplit = (e1.pointingUp && !e2.pointingUp); + bool endOrMerge = (!e1.pointingUp && e2.pointingUp); + + const QPodPoint &p1 = m_parent->m_vertices.at(e1.from); + const QPodPoint &p2 = m_parent->m_vertices.at(e2.from); + const QPodPoint &p3 = m_parent->m_vertices.at(e2.to); + qint64 d = QT_PREPEND_NAMESPACE(qPointDistanceFromLine)(p1, p2, p3); + Q_ASSERT(d != 0 || (!startOrSplit && !endOrMerge)); + + e2.type = RegularVertex; + + if (m_clockwiseOrder) { + if (startOrSplit) + e2.type = (d < 0 ? SplitVertex : StartVertex); + else if (endOrMerge) + e2.type = (d < 0 ? MergeVertex : EndVertex); + } else { + if (startOrSplit) + e2.type = (d > 0 ? SplitVertex : StartVertex); + else if (endOrMerge) + e2.type = (d > 0 ? MergeVertex : EndVertex); + } +} + +template +void QTriangulator::SimpleToMonotone::classifyVertices() +{ + for (int i = 0; i < m_edges.size(); ++i) + classifyVertex(i); +} + +template +bool QTriangulator::SimpleToMonotone::pointIsInSector(const QPodPoint &p, const QPodPoint &v1, const QPodPoint &v2, const QPodPoint &v3) +{ + bool leftOfPreviousEdge = !qPointIsLeftOfLine(p, v2, v1); + bool leftOfNextEdge = !qPointIsLeftOfLine(p, v3, v2); + + if (qPointIsLeftOfLine(v1, v2, v3)) + return leftOfPreviousEdge && leftOfNextEdge; + else + return leftOfPreviousEdge || leftOfNextEdge; +} + +template +bool QTriangulator::SimpleToMonotone::pointIsInSector(int vertex, int sector) +{ + const QPodPoint ¢er = m_parent->m_vertices.at(m_edges.at(sector).from); + // Handle degenerate edges. + while (m_parent->m_vertices.at(m_edges.at(vertex).from) == center) + vertex = m_edges.at(vertex).next; + int next = m_edges.at(sector).next; + while (m_parent->m_vertices.at(m_edges.at(next).from) == center) + next = m_edges.at(next).next; + int previous = m_edges.at(sector).previous; + while (m_parent->m_vertices.at(m_edges.at(previous).from) == center) + previous = m_edges.at(previous).previous; + + const QPodPoint &p = m_parent->m_vertices.at(m_edges.at(vertex).from); + const QPodPoint &v1 = m_parent->m_vertices.at(m_edges.at(previous).from); + const QPodPoint &v3 = m_parent->m_vertices.at(m_edges.at(next).from); + if (m_clockwiseOrder) + return pointIsInSector(p, v3, center, v1); + else + return pointIsInSector(p, v1, center, v3); +} + +template +int QTriangulator::SimpleToMonotone::findSector(int edge, int vertex) +{ + while (!pointIsInSector(vertex, edge)) { + edge = m_edges.at(m_edges.at(edge).previous).twin; + Q_ASSERT(edge != -1); + } + return edge; +} + +template +void QTriangulator::SimpleToMonotone::createDiagonal(int lower, int upper) +{ + lower = findSector(lower, upper); + upper = findSector(upper, lower); + + int prevLower = m_edges.at(lower).previous; + int prevUpper = m_edges.at(upper).previous; + + Edge e; + + e.twin = m_edges.size() + 1; + e.next = upper; + e.previous = prevLower; + e.from = m_edges.at(lower).from; + e.to = m_edges.at(upper).from; + m_edges.at(upper).previous = m_edges.at(prevLower).next = int(m_edges.size()); + m_edges.add(e); + + e.twin = m_edges.size() - 1; + e.next = lower; + e.previous = prevUpper; + e.from = m_edges.at(upper).from; + e.to = m_edges.at(lower).from; + m_edges.at(lower).previous = m_edges.at(prevUpper).next = int(m_edges.size()); + m_edges.add(e); +} + +template +void QTriangulator::SimpleToMonotone::monotoneDecomposition() +{ + if (m_edges.isEmpty()) + return; + + Q_ASSERT(!m_edgeList.root); + QDataBuffer > diagonals(m_upperVertex.size()); + + int i = 0; + for (int index = 1; index < m_edges.size(); ++index) { + if (m_parent->m_vertices.at(m_edges.at(index).from) < m_parent->m_vertices.at(m_edges.at(i).from)) + i = index; + } + Q_ASSERT(i < m_edges.size()); + int j = m_edges.at(i).previous; + Q_ASSERT(j < m_edges.size()); + m_clockwiseOrder = qPointIsLeftOfLine(m_parent->m_vertices.at((quint32)m_edges.at(i).from), + m_parent->m_vertices.at((quint32)m_edges.at(j).from), m_parent->m_vertices.at((quint32)m_edges.at(i).to)); + + classifyVertices(); + fillPriorityQueue(); + + // debug: set helpers explicitly (shouldn't be necessary) + //for (int i = 0; i < m_edges.size(); ++i) + // m_edges.at(i).helper = m_edges.at(i).upper(); + + while (!m_upperVertex.isEmpty()) { + i = m_upperVertex.last(); + Q_ASSERT(i < m_edges.size()); + m_upperVertex.pop_back(); + j = m_edges.at(i).previous; + Q_ASSERT(j < m_edges.size()); + + QRBTree::Node *leftEdgeNode = 0; + + switch (m_edges.at(i).type) { + case RegularVertex: + // If polygon interior is to the right of the vertex... + if (m_edges.at(i).pointingUp == m_clockwiseOrder) { + if (m_edges.at(i).node) { + Q_ASSERT(!m_edges.at(j).node); + if (m_edges.at(m_edges.at(i).helper).type == MergeVertex) + diagonals.add(QPair(i, m_edges.at(i).helper)); + m_edges.at(j).node = m_edges.at(i).node; + m_edges.at(i).node = 0; + m_edges.at(j).node->data = j; + m_edges.at(j).helper = i; + } else if (m_edges.at(j).node) { + Q_ASSERT(!m_edges.at(i).node); + if (m_edges.at(m_edges.at(j).helper).type == MergeVertex) + diagonals.add(QPair(i, m_edges.at(j).helper)); + m_edges.at(i).node = m_edges.at(j).node; + m_edges.at(j).node = 0; + m_edges.at(i).node->data = i; + m_edges.at(i).helper = i; + } else { + qWarning("Inconsistent polygon. (#1)"); + } + } else { + leftEdgeNode = searchEdgeLeftOfPoint(m_edges.at(i).from); + if (leftEdgeNode) { + if (m_edges.at(m_edges.at(leftEdgeNode->data).helper).type == MergeVertex) + diagonals.add(QPair(i, m_edges.at(leftEdgeNode->data).helper)); + m_edges.at(leftEdgeNode->data).helper = i; + } else { + qWarning("Inconsistent polygon. (#2)"); + } + } + break; + case SplitVertex: + leftEdgeNode = searchEdgeLeftOfPoint(m_edges.at(i).from); + if (leftEdgeNode) { + diagonals.add(QPair(i, m_edges.at(leftEdgeNode->data).helper)); + m_edges.at(leftEdgeNode->data).helper = i; + } else { + qWarning("Inconsistent polygon. (#3)"); + } + // Fall through. + case StartVertex: + if (m_clockwiseOrder) { + leftEdgeNode = searchEdgeLeftOfEdge(j); + QRBTree::Node *node = m_edgeList.newNode(); + node->data = j; + m_edges.at(j).node = node; + m_edges.at(j).helper = i; + m_edgeList.attachAfter(leftEdgeNode, node); + Q_ASSERT(m_edgeList.validate()); + } else { + leftEdgeNode = searchEdgeLeftOfEdge(i); + QRBTree::Node *node = m_edgeList.newNode(); + node->data = i; + m_edges.at(i).node = node; + m_edges.at(i).helper = i; + m_edgeList.attachAfter(leftEdgeNode, node); + Q_ASSERT(m_edgeList.validate()); + } + break; + case MergeVertex: + leftEdgeNode = searchEdgeLeftOfPoint(m_edges.at(i).from); + if (leftEdgeNode) { + if (m_edges.at(m_edges.at(leftEdgeNode->data).helper).type == MergeVertex) + diagonals.add(QPair(i, m_edges.at(leftEdgeNode->data).helper)); + m_edges.at(leftEdgeNode->data).helper = i; + } else { + qWarning("Inconsistent polygon. (#4)"); + } + // Fall through. + case EndVertex: + if (m_clockwiseOrder) { + if (m_edges.at(m_edges.at(i).helper).type == MergeVertex) + diagonals.add(QPair(i, m_edges.at(i).helper)); + if (m_edges.at(i).node) { + m_edgeList.deleteNode(m_edges.at(i).node); + Q_ASSERT(m_edgeList.validate()); + } else { + qWarning("Inconsistent polygon. (#5)"); + } + } else { + if (m_edges.at(m_edges.at(j).helper).type == MergeVertex) + diagonals.add(QPair(i, m_edges.at(j).helper)); + if (m_edges.at(j).node) { + m_edgeList.deleteNode(m_edges.at(j).node); + Q_ASSERT(m_edgeList.validate()); + } else { + qWarning("Inconsistent polygon. (#6)"); + } + } + break; + } + } + + for (int i = 0; i < diagonals.size(); ++i) + createDiagonal(diagonals.at(i).first, diagonals.at(i).second); +} + +template +bool QTriangulator::SimpleToMonotone::CompareVertices::operator () (int i, int j) const +{ + if (m_parent->m_edges.at(i).from == m_parent->m_edges.at(j).from) + return m_parent->m_edges.at(i).type > m_parent->m_edges.at(j).type; + return m_parent->m_parent->m_vertices.at(m_parent->m_edges.at(i).from) > + m_parent->m_parent->m_vertices.at(m_parent->m_edges.at(j).from); +} + +//============================================================================// +// QTriangulator::MonotoneToTriangles // +//============================================================================// +template +void QTriangulator::MonotoneToTriangles::decompose() +{ + QVector result; + QDataBuffer stack(m_parent->m_indices.size()); + m_first = 0; + // Require at least three more indices. + while (m_first + 3 <= m_parent->m_indices.size()) { + m_length = 0; + while (m_parent->m_indices.at(m_first + m_length) != T(-1)) { // Q_TRIANGULATE_END_OF_POLYGON + ++m_length; + Q_ASSERT(m_first + m_length < m_parent->m_indices.size()); + } + if (m_length < 3) { + m_first += m_length + 1; + continue; + } + + int minimum = 0; + while (less(next(minimum), minimum)) + minimum = next(minimum); + while (less(previous(minimum), minimum)) + minimum = previous(minimum); + + stack.reset(); + stack.add(minimum); + int left = previous(minimum); + int right = next(minimum); + bool stackIsOnLeftSide; + bool clockwiseOrder = leftOfEdge(minimum, left, right); + + if (less(left, right)) { + stack.add(left); + left = previous(left); + stackIsOnLeftSide = true; + } else { + stack.add(right); + right = next(right); + stackIsOnLeftSide = false; + } + + for (int count = 0; count + 2 < m_length; ++count) + { + Q_ASSERT(stack.size() >= 2); + if (less(left, right)) { + if (stackIsOnLeftSide == false) { + for (int i = 0; i + 1 < stack.size(); ++i) { + result.push_back(indices(stack.at(i + 1))); + result.push_back(indices(left)); + result.push_back(indices(stack.at(i))); + } + stack.first() = stack.last(); + stack.resize(1); + } else { + while (stack.size() >= 2 && (clockwiseOrder ^ !leftOfEdge(left, stack.at(stack.size() - 2), stack.last()))) { + result.push_back(indices(stack.at(stack.size() - 2))); + result.push_back(indices(left)); + result.push_back(indices(stack.last())); + stack.pop_back(); + } + } + stack.add(left); + left = previous(left); + stackIsOnLeftSide = true; + } else { + if (stackIsOnLeftSide == true) { + for (int i = 0; i + 1 < stack.size(); ++i) { + result.push_back(indices(stack.at(i))); + result.push_back(indices(right)); + result.push_back(indices(stack.at(i + 1))); + } + stack.first() = stack.last(); + stack.resize(1); + } else { + while (stack.size() >= 2 && (clockwiseOrder ^ !leftOfEdge(right, stack.last(), stack.at(stack.size() - 2)))) { + result.push_back(indices(stack.last())); + result.push_back(indices(right)); + result.push_back(indices(stack.at(stack.size() - 2))); + stack.pop_back(); + } + } + stack.add(right); + right = next(right); + stackIsOnLeftSide = false; + } + } + + m_first += m_length + 1; + } + m_parent->m_indices = result; +} + +//============================================================================// +// qTriangulate // +//============================================================================// + +QTriangleSet qTriangulate(const qreal *polygon, + int count, uint hint, const QTransform &matrix) +{ + QTriangleSet triangleSet; +#if 0 + if (QOpenGLExtensions::glExtensions() & QOpenGLExtensions::ElementIndexUint) { + QTriangulator triangulator; + triangulator.initialize(polygon, count, hint, matrix); + QVertexSet vertexSet = triangulator.triangulate(); + triangleSet.vertices = vertexSet.vertices; + triangleSet.indices.setDataUint(vertexSet.indices); + + } else { +#endif + QTriangulator triangulator; + triangulator.initialize(polygon, count, hint, matrix); + QVertexSet vertexSet = triangulator.triangulate(); + triangleSet.vertices = vertexSet.vertices; + triangleSet.indices.setDataUshort(vertexSet.indices); +// } + return triangleSet; +} + +QTriangleSet qTriangulate(const QVectorPath &path, + const QTransform &matrix, qreal lod) +{ + QTriangleSet triangleSet; +#if 0 + if (QOpenGLExtensions::glExtensions() & QOpenGLExtensions::ElementIndexUint) { + QTriangulator triangulator; + triangulator.initialize(path, matrix, lod); + QVertexSet vertexSet = triangulator.triangulate(); + triangleSet.vertices = vertexSet.vertices; + triangleSet.indices.setDataUint(vertexSet.indices); + } else { +#endif + QTriangulator triangulator; + triangulator.initialize(path, matrix, lod); + QVertexSet vertexSet = triangulator.triangulate(); + triangleSet.vertices = vertexSet.vertices; + triangleSet.indices.setDataUshort(vertexSet.indices); +// } + return triangleSet; +} + +QTriangleSet qTriangulate(const QPainterPath &path, + const QTransform &matrix, qreal lod) +{ + QTriangleSet triangleSet; +#if 0 + if (QOpenGLExtensions::glExtensions() & QOpenGLExtensions::ElementIndexUint) { + QTriangulator triangulator; + triangulator.initialize(path, matrix, lod); + QVertexSet vertexSet = triangulator.triangulate(); + triangleSet.vertices = vertexSet.vertices; + triangleSet.indices.setDataUint(vertexSet.indices); + } else { +#endif + QTriangulator triangulator; + triangulator.initialize(path, matrix, lod); + QVertexSet vertexSet = triangulator.triangulate(); + triangleSet.vertices = vertexSet.vertices; + triangleSet.indices.setDataUshort(vertexSet.indices); +// } + return triangleSet; +} + +QPolylineSet qPolyline(const QVectorPath &path, + const QTransform &matrix, qreal lod) +{ + QPolylineSet polyLineSet; +#if 0 + if (QOpenGLExtensions::glExtensions() & QOpenGLExtensions::ElementIndexUint) { + QTriangulator triangulator; + triangulator.initialize(path, matrix, lod); + QVertexSet vertexSet = triangulator.polyline(); + polyLineSet.vertices = vertexSet.vertices; + polyLineSet.indices.setDataUint(vertexSet.indices); + } else { +#endif + QTriangulator triangulator; + triangulator.initialize(path, matrix, lod); + QVertexSet vertexSet = triangulator.polyline(); + polyLineSet.vertices = vertexSet.vertices; + polyLineSet.indices.setDataUshort(vertexSet.indices); +// } + return polyLineSet; +} + +QPolylineSet qPolyline(const QPainterPath &path, + const QTransform &matrix, qreal lod) +{ + QPolylineSet polyLineSet; +#if 0 + if (QOpenGLExtensions::glExtensions() & QOpenGLExtensions::ElementIndexUint) { + QTriangulator triangulator; + triangulator.initialize(path, matrix, lod); + QVertexSet vertexSet = triangulator.polyline(); + polyLineSet.vertices = vertexSet.vertices; + polyLineSet.indices.setDataUint(vertexSet.indices); + } else { +#endif + QTriangulator triangulator; + triangulator.initialize(path, matrix, lod); + QVertexSet vertexSet = triangulator.polyline(); + polyLineSet.vertices = vertexSet.vertices; + polyLineSet.indices.setDataUshort(vertexSet.indices); +// } + return polyLineSet; +} + +QT_END_NAMESPACE diff --git a/src/gui/opengl/qtriangulator_p.h b/src/gui/opengl/qtriangulator_p.h new file mode 100644 index 0000000000..192bd9cb19 --- /dev/null +++ b/src/gui/opengl/qtriangulator_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTRIANGULATOR_P_H +#define QTRIANGULATOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QVertexIndexVector +{ +public: + enum Type { + UnsignedInt, + UnsignedShort + }; + + inline Type type() const { return t; } + + inline void setDataUint(const QVector &data) + { + t = UnsignedInt; + indices32 = data; + } + + inline void setDataUshort(const QVector &data) + { + t = UnsignedShort; + indices16 = data; + } + + inline const void* data() const + { + if (t == UnsignedInt) + return indices32.data(); + return indices16.data(); + } + + inline int size() const + { + if (t == UnsignedInt) + return indices32.size(); + return indices16.size(); + } + + inline QVertexIndexVector &operator = (const QVertexIndexVector &other) + { + if (t == UnsignedInt) + indices32 = other.indices32; + else + indices16 = other.indices16; + + return *this; + } + +private: + + Type t; + QVector indices32; + QVector indices16; +}; + +struct Q_GUI_EXPORT QTriangleSet +{ + inline QTriangleSet() { } + inline QTriangleSet(const QTriangleSet &other) : vertices(other.vertices), indices(other.indices) { } + QTriangleSet &operator = (const QTriangleSet &other) {vertices = other.vertices; indices = other.indices; return *this;} + + // The vertices of a triangle are given by: (x[i[n]], y[i[n]]), (x[j[n]], y[j[n]]), (x[k[n]], y[k[n]]), n = 0, 1, ... + QVector vertices; // [x[0], y[0], x[1], y[1], x[2], ...] + QVertexIndexVector indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...] +}; + +struct Q_GUI_EXPORT QPolylineSet +{ + inline QPolylineSet() { } + inline QPolylineSet(const QPolylineSet &other) : vertices(other.vertices), indices(other.indices) { } + QPolylineSet &operator = (const QPolylineSet &other) {vertices = other.vertices; indices = other.indices; return *this;} + + QVector vertices; // [x[0], y[0], x[1], y[1], x[2], ...] + QVertexIndexVector indices; // End of polyline is marked with -1. +}; + +// The vertex coordinates of the returned triangle set will be rounded to a grid with a mesh size +// of 1/32. The polygon is first transformed, then scaled by 32, the coordinates are rounded to +// integers, the polygon is triangulated, and then scaled back by 1/32. +// 'hint' should be a combination of QVectorPath::Hints. +// 'lod' is the level of detail. Default is 1. Curves are split into more lines when 'lod' is higher. +QTriangleSet qTriangulate(const qreal *polygon, int count, uint hint = QVectorPath::PolygonHint | QVectorPath::OddEvenFill, const QTransform &matrix = QTransform()); +QTriangleSet qTriangulate(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1); +QTriangleSet Q_GUI_EXPORT qTriangulate(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1); +QPolylineSet qPolyline(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1); +QPolylineSet Q_GUI_EXPORT qPolyline(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1); + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp index c8870cd5d3..f64bd52ec2 100644 --- a/src/gui/painting/qpaintengine.cpp +++ b/src/gui/painting/qpaintengine.cpp @@ -154,7 +154,7 @@ QFont QTextItem::font() const different painter backends we support. We provide one paint engine for each window system and painting framework we support. This includes X11 on Unix/Linux and CoreGraphics on Mac OS X. In addition we provide QPaintEngine - implementations for OpenGL (accessible through QGLWidget) and PostScript + implementations for OpenGL (accessible through QOpenGLWidget) and PostScript (accessible through QPSPrinter on X11). Additionally there is a raster-based paint engine that is a fallback for when an engine does not support a certain capability. diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index d9ab506c94..9674f04ba1 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -212,7 +212,7 @@ public: virtual void beginNativePainting() {} virtual void endNativePainting() {} - // ### Qt5: remove, once QtOpenGL is merged into QtGui and QtWidgets + // ### Qt5: remove, once QtGui is merged into QtGui and QtWidgets // Return a pixmap filter of "type" that can render the parameters // in "prototype". The returned filter is owned by the engine and // will be destroyed when the engine is destroyed. The "prototype" diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 75e7f8e79a..fe9914bd8f 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -1351,7 +1351,7 @@ void QPainterPrivate::updateState(QPainterState *newState) and embedded devices supporting the OpenGL 2.0 or OpenGL/ES 2.0 specification. This includes most graphics chips produced in the last couple of years. The engine can be enabled by using QPainter - onto a QGLWidget or by passing \c {-graphicssystem opengl} on the + onto a QOpenGLWidget or by passing \c {-graphicssystem opengl} on the command line when the underlying system supports it. \o OpenVG - This backend implements the Khronos standard for 2D diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index 1035b665a3..421c1dd2de 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -316,7 +316,7 @@ private: friend class QStackTextEngine; friend class QTextLine; friend struct QScriptLine; - friend class QGLContext; + friend class QOpenGLContext; friend class QWin32PaintEngine; friend class QAlphaPaintEngine; friend class QPainterPath; diff --git a/src/gui/text/qglyphrun.h b/src/gui/text/qglyphrun.h index da88bc72f9..bb5b99f7f9 100644 --- a/src/gui/text/qglyphrun.h +++ b/src/gui/text/qglyphrun.h @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef QGLYPHRUN_H -#define QGLYPHRUN_H +#ifndef QOpenGLYPHRUN_H +#define QOpenGLYPHRUN_H #include #include @@ -113,4 +113,4 @@ QT_END_HEADER #endif // QT_NO_RAWFONT -#endif // QGLYPHS_H +#endif // QOpenGLYPHS_H diff --git a/src/gui/text/qglyphrun_p.h b/src/gui/text/qglyphrun_p.h index b632678971..96a80bebe9 100644 --- a/src/gui/text/qglyphrun_p.h +++ b/src/gui/text/qglyphrun_p.h @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef QGLYPHRUN_P_H -#define QGLYPHRUN_P_H +#ifndef QOpenGLYPHRUN_P_H +#define QOpenGLYPHRUN_P_H // // W A R N I N G @@ -119,6 +119,6 @@ QT_END_NAMESPACE QT_END_HEADER -#endif // QGLYPHS_P_H +#endif // QOpenGLYPHS_P_H #endif // QT_NO_RAWFONT diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 10c494dec9..bed0da62da 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -139,7 +139,7 @@ QT_BEGIN_NAMESPACE can be used to indicate that the QStaticText should use additional caches, if possible, to improve performance at the expense of memory. In particular, setting the performance hint AggressiveCaching on the QStaticText will improve performance when using the OpenGL graphics - system or when drawing to a QGLWidget. + system or when drawing to a QOpenGLWidget. \value ModerateCaching Do basic caching for high performance at a low memory cost. \value AggressiveCaching Use additional caching when available. This may improve performance diff --git a/src/modules/qt_gui.pri b/src/modules/qt_gui.pri index 1fd53e587c..2dfbb4a604 100644 --- a/src/modules/qt_gui.pri +++ b/src/modules/qt_gui.pri @@ -11,4 +11,5 @@ QT.gui.libs = $$QT_MODULE_LIB_BASE QT.gui.plugins = $$QT_MODULE_PLUGIN_BASE QT.gui.imports = $$QT_MODULE_IMPORT_BASE QT.gui.depends = core +QT.gui.CONFIG = opengl QT.gui.DEFINES = QT_GUI_LIB diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index 05a612c311..aebdce6e01 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -44,7 +44,7 @@ #include "qpaintengineex_opengl2_p.h" #include "qglshadercache_p.h" -#include +#include #if defined(QT_DEBUG) #include @@ -54,12 +54,12 @@ QT_BEGIN_NAMESPACE -class QGLEngineSharedShadersResource : public QGLSharedResource +class QGLEngineSharedShadersResource : public QOpenGLSharedResource { public: - QGLEngineSharedShadersResource(QGuiGLContext *ctx) - : QGLSharedResource(ctx->shareGroup()) - , m_shaders(new QGLEngineSharedShaders(QGLContext::fromGuiGLContext(ctx))) + QGLEngineSharedShadersResource(QOpenGLContext *ctx) + : QOpenGLSharedResource(ctx->shareGroup()) + , m_shaders(new QGLEngineSharedShaders(QGLContext::fromOpenGLContext(ctx))) { } @@ -74,7 +74,7 @@ public: m_shaders = 0; } - void freeResource(QGuiGLContext *) + void freeResource(QOpenGLContext *) { } @@ -88,16 +88,16 @@ class QGLShaderStorage { public: QGLEngineSharedShaders *shadersForThread(const QGLContext *context) { - QGLMultiGroupSharedResource *&shaders = m_storage.localData(); + QOpenGLMultiGroupSharedResource *&shaders = m_storage.localData(); if (!shaders) - shaders = new QGLMultiGroupSharedResource; + shaders = new QOpenGLMultiGroupSharedResource; QGLEngineSharedShadersResource *resource = shaders->value(context->contextHandle()); return resource ? resource->shaders() : 0; } private: - QThreadStorage m_storage; + QThreadStorage m_storage; }; Q_GLOBAL_STATIC(QGLShaderStorage, qt_shader_storage); diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp index bd408ffdc4..6ca09ba140 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache.cpp +++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp @@ -55,14 +55,14 @@ public: } private: - QGLMultiGroupSharedResource m_resource; + QOpenGLMultiGroupSharedResource m_resource; QMutex m_mutex; }; Q_GLOBAL_STATIC(QGL2GradientCacheWrapper, qt_gradient_caches) -QGL2GradientCache::QGL2GradientCache(QGuiGLContext *ctx) - : QGLSharedResource(ctx->shareGroup()) +QGL2GradientCache::QGL2GradientCache(QOpenGLContext *ctx) + : QOpenGLSharedResource(ctx->shareGroup()) { } @@ -82,7 +82,7 @@ void QGL2GradientCache::invalidateResource() cache.clear(); } -void QGL2GradientCache::freeResource(QGuiGLContext *) +void QGL2GradientCache::freeResource(QOpenGLContext *) { cleanCache(); } diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h index 1b001c3405..600085a75f 100644 --- a/src/opengl/gl2paintengineex/qglgradientcache_p.h +++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE -class QGL2GradientCache : public QGLSharedResource +class QGL2GradientCache : public QOpenGLSharedResource { struct CacheInfo { @@ -76,14 +76,14 @@ class QGL2GradientCache : public QGLSharedResource public: static QGL2GradientCache *cacheForContext(const QGLContext *context); - QGL2GradientCache(QGuiGLContext *); + QGL2GradientCache(QOpenGLContext *); ~QGL2GradientCache(); GLuint getBuffer(const QGradient &gradient, qreal opacity); inline int paletteSize() const { return 1024; } void invalidateResource(); - void freeResource(QGuiGLContext *ctx); + void freeResource(QOpenGLContext *ctx); private: inline int maxCacheSize() const { return 60; } diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp index 214bfa5b47..af6cb53a3a 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp @@ -59,7 +59,7 @@ QGLTextureGlyphCache::QGLTextureGlyphCache(QFontEngineGlyphCache::Type type, con , m_serialNumber(qgltextureglyphcache_serial_number.fetchAndAddRelaxed(1)) { #ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG - qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, QGuiGLContext::currentContext()); + qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, QOpenGLContext::currentContext()); #endif m_vertexCoordinateArray[0] = -1.0f; m_vertexCoordinateArray[1] = -1.0f; diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h index 2fcc551667..7b7da9d8e8 100644 --- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h +++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h @@ -63,10 +63,10 @@ QT_BEGIN_NAMESPACE class QGL2PaintEngineExPrivate; -struct QGLGlyphTexture : public QGLSharedResource +struct QGLGlyphTexture : public QOpenGLSharedResource { QGLGlyphTexture(const QGLContext *ctx) - : QGLSharedResource(ctx->contextHandle()->shareGroup()) + : QOpenGLSharedResource(ctx->contextHandle()->shareGroup()) , m_width(0) , m_height(0) { @@ -78,9 +78,9 @@ struct QGLGlyphTexture : public QGLSharedResource #endif } - void freeResource(QGuiGLContext *context) + void freeResource(QOpenGLContext *context) { - const QGLContext *ctx = QGLContext::fromGuiGLContext(context); + const QGLContext *ctx = QGLContext::fromOpenGLContext(context); #ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG qDebug("~QGLGlyphTexture() %p for context %p.", this, ctx); #endif @@ -136,7 +136,7 @@ public: inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; } - inline const QGuiGLContextGroup *contextGroup() const { return m_textureResource ? m_textureResource->group() : 0; } + inline const QOpenGLContextGroup *contextGroup() const { return m_textureResource ? m_textureResource->group() : 0; } inline int serialNumber() const { return m_serialNumber; } diff --git a/src/opengl/gl2paintengineex/qtriangulator_p.h b/src/opengl/gl2paintengineex/qtriangulator_p.h index 04a219c255..a8e7553770 100644 --- a/src/opengl/gl2paintengineex/qtriangulator_p.h +++ b/src/opengl/gl2paintengineex/qtriangulator_p.h @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE -class Q_OPENGL_EXPORT QVertexIndexVector +class QVertexIndexVector { public: enum Type { @@ -111,7 +111,7 @@ private: QVector indices16; }; -struct Q_OPENGL_EXPORT QTriangleSet +struct QTriangleSet { inline QTriangleSet() { } inline QTriangleSet(const QTriangleSet &other) : vertices(other.vertices), indices(other.indices) { } @@ -122,7 +122,7 @@ struct Q_OPENGL_EXPORT QTriangleSet QVertexIndexVector indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...] }; -struct Q_OPENGL_EXPORT QPolylineSet +struct QPolylineSet { inline QPolylineSet() { } inline QPolylineSet(const QPolylineSet &other) : vertices(other.vertices), indices(other.indices) { } @@ -139,9 +139,9 @@ struct Q_OPENGL_EXPORT QPolylineSet // 'lod' is the level of detail. Default is 1. Curves are split into more lines when 'lod' is higher. QTriangleSet qTriangulate(const qreal *polygon, int count, uint hint = QVectorPath::PolygonHint | QVectorPath::OddEvenFill, const QTransform &matrix = QTransform()); QTriangleSet qTriangulate(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1); -QTriangleSet Q_OPENGL_EXPORT qTriangulate(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1); +QTriangleSet qTriangulate(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1); QPolylineSet qPolyline(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1); -QPolylineSet Q_OPENGL_EXPORT qPolyline(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1); +QPolylineSet qPolyline(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1); QT_END_NAMESPACE diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index f51882841b..a78c602701 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -55,7 +55,7 @@ #include "gl2paintengineex/qpaintengineex_opengl2_p.h" -#include +#include #include #include @@ -1501,11 +1501,15 @@ const QGLContext *qt_gl_transfer_context(const QGLContext *ctx) QGLContextPrivate::QGLContextPrivate(QGLContext *context) : internal_context(false) , q_ptr(context) + , texture_destroyer(0) , functions(0) { group = new QGLContextGroup(context); - texture_destroyer = new QGLTextureDestroyer; - texture_destroyer->moveToThread(qApp->thread()); + + if (qApp) { + texture_destroyer = new QGLTextureDestroyer; + texture_destroyer->moveToThread(qApp->thread()); + } } QGLContextPrivate::~QGLContextPrivate() @@ -1605,7 +1609,7 @@ static void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, boo img = img.mirrored(); } -Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) +QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) { QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32); @@ -3076,8 +3080,8 @@ void QGLContext::setInitialized(bool on) const QGLContext* QGLContext::currentContext() { - if (const QGuiGLContext *threadContext = QGuiGLContext::currentContext()) { - return QGLContext::fromGuiGLContext(const_cast(threadContext)); + if (const QOpenGLContext *threadContext = QOpenGLContext::currentContext()) { + return QGLContext::fromOpenGLContext(const_cast(threadContext)); } return 0; } @@ -4664,7 +4668,7 @@ void QGLWidget::drawTexture(const QPointF &point, GLuint textureId, GLenum textu Q_GLOBAL_STATIC(QGLEngineThreadStorage, qt_gl_2_engine) -Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine() +QPaintEngine* qt_qgl_paint_engine() { return qt_gl_2_engine()->engine(); } @@ -4934,12 +4938,12 @@ void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWi Q_GLOBAL_STATIC(QString, qt_gl_lib_name) -Q_OPENGL_EXPORT void qt_set_gl_library_name(const QString& name) +void qt_set_gl_library_name(const QString& name) { qt_gl_lib_name()->operator=(name); } -Q_OPENGL_EXPORT const QString qt_gl_library_name() +const QString qt_gl_library_name() { if (qt_gl_lib_name()->isNull()) { # if defined(QT_OPENGL_ES_2) diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index a12cddcca4..665dcac412 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -338,8 +338,8 @@ public: static const QGLContext* currentContext(); - static QGLContext *fromGuiGLContext(QGuiGLContext *platformContext); - QGuiGLContext *contextHandle() const; + static QGLContext *fromOpenGLContext(QOpenGLContext *platformContext); + QOpenGLContext *contextHandle() const; protected: virtual bool chooseContext(const QGLContext* shareContext = 0); @@ -359,7 +359,7 @@ protected: static QGLContext* currentCtx; private: - QGLContext(QGuiGLContext *windowContext); + QGLContext(QOpenGLContext *windowContext); QScopedPointer d_ptr; diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 58efc7f7fd..6f418a9818 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -61,11 +61,11 @@ #include "QtCore/qhash.h" #include "QtCore/qatomic.h" #include "QtWidgets/private/qwidget_p.h" -#include "QtGui/private/qguiglcontext_qpa_p.h" +#include "QtGui/private/qopenglcontext_p.h" #include "qcache.h" #include "qglpaintdevice_p.h" -#include +#include QT_BEGIN_NAMESPACE @@ -209,7 +209,7 @@ private: // Get the context that resources for "ctx" will transfer to once // "ctx" is destroyed. Returns null if nothing is sharing with ctx. -Q_OPENGL_EXPORT const QGLContext *qt_gl_transfer_context(const QGLContext *); +const QGLContext *qt_gl_transfer_context(const QGLContext *); // GL extension definitions class QGLExtensions { @@ -298,7 +298,7 @@ public: void syncGlState(); // Makes sure the GL context's state is what we think it is void swapRegion(const QRegion ®ion); - QGuiGLContext *guiGlContext; + QOpenGLContext *guiGlContext; void setupSharing(); QGLFormat glFormat; @@ -528,18 +528,18 @@ QGLTexture* QGLTextureCache::getTexture(QGLContext *ctx, qint64 key) return m_cache.object(cacheKey); } -extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine(); +extern QPaintEngine* qt_qgl_paint_engine(); // Put a guard around a GL object identifier and its context. // When the context goes away, a shared context will be used // in its place. If there are no more shared contexts, then // the identifier is returned as zero - it is assumed that the // context destruction cleaned up the identifier in this case. -class Q_OPENGL_EXPORT QGLSharedResourceGuardBase : public QGLSharedResource +class QGLSharedResourceGuardBase : public QOpenGLSharedResource { public: QGLSharedResourceGuardBase(QGLContext *context, GLuint id) - : QGLSharedResource(context->contextHandle()->shareGroup()) + : QOpenGLSharedResource(context->contextHandle()->shareGroup()) , m_id(id) { } @@ -555,10 +555,10 @@ protected: m_id = 0; } - void freeResource(QGuiGLContext *context) + void freeResource(QOpenGLContext *context) { if (m_id) { - freeResource(QGLContext::fromGuiGLContext(context), m_id); + freeResource(QGLContext::fromOpenGLContext(context), m_id); } } diff --git a/src/opengl/qgl_qpa.cpp b/src/opengl/qgl_qpa.cpp index e6c135bb7f..46dfd54adf 100644 --- a/src/opengl/qgl_qpa.cpp +++ b/src/opengl/qgl_qpa.cpp @@ -45,7 +45,7 @@ #include #include -#include +#include #include #include @@ -110,9 +110,9 @@ QSurfaceFormat QGLFormat::toSurfaceFormat(const QGLFormat &format) void QGLContextPrivate::setupSharing() { Q_Q(QGLContext); - QGuiGLContext *sharedContext = guiGlContext->shareContext(); + QOpenGLContext *sharedContext = guiGlContext->shareContext(); if (sharedContext) { - QGLContext *actualSharedContext = QGLContext::fromGuiGLContext(sharedContext); + QGLContext *actualSharedContext = QGLContext::fromOpenGLContext(sharedContext); sharing = true; QGLContextGroup::addShare(q, actualSharedContext); } @@ -149,8 +149,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) } delete d->guiGlContext; - QGuiGLContext *shareGlContext = shareContext ? shareContext->d_func()->guiGlContext : 0; - d->guiGlContext = new QGuiGLContext; + QOpenGLContext *shareGlContext = shareContext ? shareContext->d_func()->guiGlContext : 0; + d->guiGlContext = new QOpenGLContext; d->guiGlContext->setFormat(winFormat); d->guiGlContext->setShareContext(shareGlContext); d->valid = d->guiGlContext->create(); @@ -286,7 +286,7 @@ class QGLTemporaryContextPrivate { public: QWindow *window; - QGuiGLContext *context; + QOpenGLContext *context; QGLContext *oldContext; }; @@ -301,7 +301,7 @@ QGLTemporaryContext::QGLTemporaryContext(bool, QWidget *) d->window->setGeometry(QRect(0, 0, 3, 3)); d->window->create(); - d->context = new QGuiGLContext; + d->context = new QOpenGLContext; d->context->create(); d->context->makeCurrent(d->window); } @@ -378,7 +378,7 @@ void QGLWidget::setColormap(const QGLColormap & c) Q_UNUSED(c); } -QGLContext::QGLContext(QGuiGLContext *context) +QGLContext::QGLContext(QOpenGLContext *context) : d_ptr(new QGLContextPrivate(this)) { Q_D(QGLContext); @@ -389,7 +389,7 @@ QGLContext::QGLContext(QGuiGLContext *context) d->setupSharing(); } -QGuiGLContext *QGLContext::contextHandle() const +QOpenGLContext *QGLContext::contextHandle() const { Q_D(const QGLContext); return d->guiGlContext; @@ -398,7 +398,7 @@ QGuiGLContext *QGLContext::contextHandle() const /*! Returns a OpenGL context for the window context specified by \a windowContext */ -QGLContext *QGLContext::fromGuiGLContext(QGuiGLContext *context) +QGLContext *QGLContext::fromOpenGLContext(QOpenGLContext *context) { if (!context) return 0; diff --git a/src/opengl/qglbuffer.cpp b/src/opengl/qglbuffer.cpp index 53f27392b0..c1128a0ebd 100644 --- a/src/opengl/qglbuffer.cpp +++ b/src/opengl/qglbuffer.cpp @@ -334,7 +334,7 @@ bool QGLBuffer::read(int offset, void *data, int count) { #if !defined(QT_OPENGL_ES) Q_D(QGLBuffer); - if (!glGetBufferSubData || !d->guard.id()) + if (!glGetBufferSubData || !d->guard->id()) return false; while (glGetError() != GL_NO_ERROR) ; // Clear error state. glGetBufferSubData(d->type, offset, count, data); @@ -421,7 +421,7 @@ bool QGLBuffer::bind() Q_D(const QGLBuffer); GLuint bufferId = d->guard ? d->guard->id() : 0; if (bufferId) { - if (d->guard->group() != QGuiGLContextGroup::currentContextGroup()) { + if (d->guard->group() != QOpenGLContextGroup::currentContextGroup()) { #ifndef QT_NO_DEBUG qWarning("QGLBuffer::bind: buffer is not valid in the current context"); #endif diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h index 2ef8a0169c..991fbba8c7 100644 --- a/src/opengl/qglextensions_p.h +++ b/src/opengl/qglextensions_p.h @@ -855,10 +855,10 @@ struct QGLExtensionFuncs #endif extern bool qt_resolve_framebufferobject_extensions(QGLContext *ctx); -bool Q_OPENGL_EXPORT qt_resolve_buffer_extensions(QGLContext *ctx); +bool qt_resolve_buffer_extensions(QGLContext *ctx); bool qt_resolve_version_1_3_functions(QGLContext *ctx); -bool Q_OPENGL_EXPORT qt_resolve_version_2_0_functions(QGLContext *ctx); +bool qt_resolve_version_2_0_functions(QGLContext *ctx); bool qt_resolve_stencil_face_extension(QGLContext *ctx); bool qt_resolve_frag_program_extensions(QGLContext *ctx); diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index 29168441b3..e3f12e42c8 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE -extern Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool, bool); +extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool); #define QGL_FUNC_CONTEXT const QGLContext *ctx = QGLContext::currentContext(); #define QGL_FUNCP_CONTEXT const QGLContext *ctx = QGLContext::currentContext(); diff --git a/src/opengl/qglfunctions.cpp b/src/opengl/qglfunctions.cpp index 534c6c8bbf..227e6cc176 100644 --- a/src/opengl/qglfunctions.cpp +++ b/src/opengl/qglfunctions.cpp @@ -41,7 +41,7 @@ #include "qglfunctions.h" #include "qgl_p.h" -#include "QtGui/private/qguiglcontext_qpa_p.h" +#include "QtGui/private/qopenglcontext_p.h" QT_BEGIN_NAMESPACE @@ -140,11 +140,11 @@ QT_BEGIN_NAMESPACE */ // Hidden private fields for additional extension data. -struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QGLSharedResource +struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QOpenGLSharedResource { - QGLFunctionsPrivateEx(QGuiGLContext *context) - : QGLFunctionsPrivate(QGLContext::fromGuiGLContext(context)) - , QGLSharedResource(context->shareGroup()) + QGLFunctionsPrivateEx(QOpenGLContext *context) + : QGLFunctionsPrivate(QGLContext::fromOpenGLContext(context)) + , QOpenGLSharedResource(context->shareGroup()) , m_features(-1) {} void invalidateResource() @@ -152,7 +152,7 @@ struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QGLSharedResou m_features = -1; } - void freeResource(QGuiGLContext *) + void freeResource(QOpenGLContext *) { // no gl resources to free } @@ -160,7 +160,7 @@ struct QGLFunctionsPrivateEx : public QGLFunctionsPrivate, public QGLSharedResou int m_features; }; -Q_GLOBAL_STATIC(QGLMultiGroupSharedResource, qt_gl_functions_resource) +Q_GLOBAL_STATIC(QOpenGLMultiGroupSharedResource, qt_gl_functions_resource) static QGLFunctionsPrivateEx *qt_gl_functions(const QGLContext *context = 0) { diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 156c40f394..ee4e9547ca 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -91,7 +91,7 @@ #include -#include +#include #include #include @@ -100,7 +100,7 @@ QT_BEGIN_NAMESPACE -extern Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool, bool); +extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool); QGLContext* QGLPBufferGLPaintDevice::context() const diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp index 7b3f5d998d..0163d60f0c 100644 --- a/src/opengl/qglshaderprogram.cpp +++ b/src/opengl/qglshaderprogram.cpp @@ -958,7 +958,7 @@ bool QGLShaderProgram::bind() if (!d->linked && !link()) return false; #ifndef QT_NO_DEBUG - if (d->programGuard->group() != QGuiGLContextGroup::currentContextGroup()) { + if (d->programGuard->group() != QOpenGLContextGroup::currentContextGroup()) { qWarning("QGLShaderProgram::bind: program is not valid in the current context."); return false; } @@ -980,7 +980,7 @@ void QGLShaderProgram::release() { #ifndef QT_NO_DEBUG Q_D(QGLShaderProgram); - if (d->programGuard->group() != QGuiGLContextGroup::currentContextGroup()) + if (d->programGuard->group() != QOpenGLContextGroup::currentContextGroup()) qWarning("QGLShaderProgram::release: program is not valid in the current context."); #endif #if defined(QT_OPENGL_ES_2) @@ -991,9 +991,6 @@ void QGLShaderProgram::release() #endif } -#undef ctx -#define ctx d->programGuard.context() - /*! Returns the OpenGL identifier associated with this shader program. diff --git a/src/opengl/util/README-GLSL b/src/opengl/util/README-GLSL deleted file mode 100644 index ff20eb45b2..0000000000 --- a/src/opengl/util/README-GLSL +++ /dev/null @@ -1,18 +0,0 @@ -Use of GLSL for vertex and fragment programs in Qt ---------------------------------------------------- - -We don't compile the *.glsl files because we don't want the build process of -Qt to require cgc from nVidia to build the fragment programs. - -The script src/opengl/util/glsl_to_include.sh will compile a GLSL program to a file -that can be included in a C(++) program. The file is the output from cgc -quoted as a string. - -This can be done manually by: - -./glsl_to_include.sh radial.glsl -./glsl_to_include.sh conical.glsl - -This will produce the files radial.frag and radial.glsl_quoted. -(and also conical.frag and conical.glsl_quoted) -These files are included by qpaintengine_opengl.cpp diff --git a/src/opengl/util/brush_painter.glsl b/src/opengl/util/brush_painter.glsl deleted file mode 100644 index 6c4acdf924..0000000000 --- a/src/opengl/util/brush_painter.glsl +++ /dev/null @@ -1,7 +0,0 @@ -// fast brush painter for composition modes which can be implemented with blendfuncs -// no mask, used for fast filling of aliased primitives (or multisampled) - -void main() -{ - gl_FragColor = brush(); -} diff --git a/src/opengl/util/brushes.conf b/src/opengl/util/brushes.conf deleted file mode 100644 index 93e2b3b295..0000000000 --- a/src/opengl/util/brushes.conf +++ /dev/null @@ -1,6 +0,0 @@ -FRAGMENT_PROGRAM_BRUSH_SOLID solid_brush.glsl -FRAGMENT_PROGRAM_BRUSH_RADIAL radial_brush.glsl -FRAGMENT_PROGRAM_BRUSH_CONICAL conical_brush.glsl -FRAGMENT_PROGRAM_BRUSH_LINEAR linear_brush.glsl -FRAGMENT_PROGRAM_BRUSH_TEXTURE texture_brush.glsl -FRAGMENT_PROGRAM_BRUSH_PATTERN pattern_brush.glsl diff --git a/src/opengl/util/composition_mode_colorburn.glsl b/src/opengl/util/composition_mode_colorburn.glsl deleted file mode 100644 index c913b9737f..0000000000 --- a/src/opengl/util/composition_mode_colorburn.glsl +++ /dev/null @@ -1,13 +0,0 @@ -// Dca' = Sca.Da + Dca.Sa <= Sa.Da ? -// Sca.(1 - Da) + Dca.(1 - Sa) -// Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa) -// Da' = Sa + Da - Sa.Da -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - result.rgb = mix(src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), - src.a * (src.rgb * dst.a + dst.rgb * src.a - src.a * dst.a) / max(src.rgb, 0.00001) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), - step(src.a * dst.a, src.rgb * dst.a + dst.rgb * src.a)); - result.a = src.a + dst.a - src.a * dst.a; - return result; -} diff --git a/src/opengl/util/composition_mode_colordodge.glsl b/src/opengl/util/composition_mode_colordodge.glsl deleted file mode 100644 index b75e83cf4e..0000000000 --- a/src/opengl/util/composition_mode_colordodge.glsl +++ /dev/null @@ -1,15 +0,0 @@ -// Dca' = Sca.Da + Dca.Sa <= Sa.Da ? -// Dca.Sa/(1 - Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa) : -// Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) -// Da' = Sa + Da - Sa.Da -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - vec3 temp = src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a); - result.rgb = mix(dst.rgb * src.a / max(1.0 - src.rgb / max(src.a, 0.000001), 0.000001) + temp, - src.a * dst.a + temp, - step(src.a * dst.a, src.rgb * dst.a + dst.rgb * src.a)); - - result.a = src.a + dst.a - src.a * dst.a; - return result; -} diff --git a/src/opengl/util/composition_mode_darken.glsl b/src/opengl/util/composition_mode_darken.glsl deleted file mode 100644 index 8bbb82b3ce..0000000000 --- a/src/opengl/util/composition_mode_darken.glsl +++ /dev/null @@ -1,9 +0,0 @@ -// Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) -// Da' = Sa + Da - Sa.Da -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - result.rgb = min(src.rgb * dst.a, dst.rgb * src.a) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a); - result.a = src.a + dst.a - src.a * dst.a; - return result; -} diff --git a/src/opengl/util/composition_mode_difference.glsl b/src/opengl/util/composition_mode_difference.glsl deleted file mode 100644 index 3c46ec71f2..0000000000 --- a/src/opengl/util/composition_mode_difference.glsl +++ /dev/null @@ -1,9 +0,0 @@ -// Dca' = Sca + Dca - 2.min(Sca.Da, Dca.Sa) -// Da' = Sa + Da - Sa.Da -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - result.rgb = src.rgb + dst.rgb - 2.0 * min(src.rgb * dst.a, dst.rgb * src.a); - result.a = src.a + dst.a - src.a * dst.a; - return result; -} diff --git a/src/opengl/util/composition_mode_exclusion.glsl b/src/opengl/util/composition_mode_exclusion.glsl deleted file mode 100644 index 59c2da99ea..0000000000 --- a/src/opengl/util/composition_mode_exclusion.glsl +++ /dev/null @@ -1,9 +0,0 @@ -// Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) -// Da' = Sa + Da - Sa.Da -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - result.rgb = (src.rgb * dst.a + dst.rgb * src.a - 2.0 * src.rgb * dst.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a); - result.a = src.a + dst.a - src.a * dst.a; - return result; -} diff --git a/src/opengl/util/composition_mode_hardlight.glsl b/src/opengl/util/composition_mode_hardlight.glsl deleted file mode 100644 index 4ea355029d..0000000000 --- a/src/opengl/util/composition_mode_hardlight.glsl +++ /dev/null @@ -1,14 +0,0 @@ -// Dca' = 2.Sca < Sa ? -// 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) : -// Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) -// Da' = Sa + Da - Sa.Da -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - result.rgb = mix(2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), - src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), - step(src.a, 2.0 * src.rgb)); - result.a = src.a + dst.a - src.a * dst.a; - - return result; -} diff --git a/src/opengl/util/composition_mode_lighten.glsl b/src/opengl/util/composition_mode_lighten.glsl deleted file mode 100644 index 13ef507a4c..0000000000 --- a/src/opengl/util/composition_mode_lighten.glsl +++ /dev/null @@ -1,9 +0,0 @@ -// Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) -// Da' = Sa + Da - Sa.Da -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - result.rgb = max(src.rgb * dst.a, dst.rgb * src.a) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a); - result.a = src.a + dst.a - src.a * dst.a; - return result; -} diff --git a/src/opengl/util/composition_mode_multiply.glsl b/src/opengl/util/composition_mode_multiply.glsl deleted file mode 100644 index f90b7f00ad..0000000000 --- a/src/opengl/util/composition_mode_multiply.glsl +++ /dev/null @@ -1,9 +0,0 @@ -// Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) -// Da' = Sa + Da - Sa.Da -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - result.rgb = src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a); - result.a = src.a + dst.a - src.a * dst.a; - return result; -} diff --git a/src/opengl/util/composition_mode_overlay.glsl b/src/opengl/util/composition_mode_overlay.glsl deleted file mode 100644 index f621bdee96..0000000000 --- a/src/opengl/util/composition_mode_overlay.glsl +++ /dev/null @@ -1,13 +0,0 @@ -// Dca' = 2.Dca < Da ? -// 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) -// Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) -// Da' = Sa + Da - Sa.Da -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - result.rgb = mix(2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), - src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), - step(dst.a, 2.0 * dst.rgb)); - result.a = src.a + dst.a - src.a * dst.a; - return result; -} diff --git a/src/opengl/util/composition_mode_screen.glsl b/src/opengl/util/composition_mode_screen.glsl deleted file mode 100644 index 8f4f010032..0000000000 --- a/src/opengl/util/composition_mode_screen.glsl +++ /dev/null @@ -1,6 +0,0 @@ -// Dca' = Sca + Dca - Sca.Dca -// Da' = Sa + Da - Sa.Da -vec4 composite(vec4 src, vec4 dst) -{ - return src + dst - src * dst; -} diff --git a/src/opengl/util/composition_mode_softlight.glsl b/src/opengl/util/composition_mode_softlight.glsl deleted file mode 100644 index e4c1f89156..0000000000 --- a/src/opengl/util/composition_mode_softlight.glsl +++ /dev/null @@ -1,22 +0,0 @@ -// if 2.Sca <= Sa -// Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) -// otherwise if 2.Sca > Sa and 4.Dca <= Da -// Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) -// otherwise if 2.Sca > Sa and 4.Dca > Da -// Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) -// Da' = Sa + Da - Sa.Da - -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - float da = max(dst.a, 0.00001); - vec3 dst_np = dst.rgb / da; - result.rgb = mix(dst.rgb * (src.a + (2.0 * src.rgb - src.a) * (1.0 - dst_np)), - mix(dst.rgb * src.a + dst.a * (2.0 * src.rgb - src.a) * ((16.0 * dst_np - 12.0) * dst_np + 3.0) * dst_np, - dst.rgb * src.a + dst.a * (2.0 * src.rgb - src.a) * (sqrt(dst_np) - dst_np), - step(dst.a, 4.0 * dst.rgb)), - step(src.a, 2.0 * src.rgb)) - + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a); - result.a = src.a + dst.a - src.a * dst.a; - return result; -} diff --git a/src/opengl/util/composition_modes.conf b/src/opengl/util/composition_modes.conf deleted file mode 100644 index df52830b99..0000000000 --- a/src/opengl/util/composition_modes.conf +++ /dev/null @@ -1,12 +0,0 @@ -COMPOSITION_MODES_SIMPLE_PORTER_DUFF simple_porter_duff.glsl -COMPOSITION_MODES_MULTIPLY composition_mode_multiply.glsl -COMPOSITION_MODES_SCREEN composition_mode_screen.glsl -COMPOSITION_MODES_OVERLAY composition_mode_overlay.glsl -COMPOSITION_MODES_DARKEN composition_mode_darken.glsl -COMPOSITION_MODES_LIGHTEN composition_mode_lighten.glsl -COMPOSITION_MODES_COLORDODGE composition_mode_colordodge.glsl -COMPOSITION_MODES_COLORBURN composition_mode_colorburn.glsl -COMPOSITION_MODES_HARDLIGHT composition_mode_hardlight.glsl -COMPOSITION_MODES_SOFTLIGHT composition_mode_softlight.glsl -COMPOSITION_MODES_DIFFERENCE composition_mode_difference.glsl -COMPOSITION_MODES_EXCLUSION composition_mode_exclusion.glsl diff --git a/src/opengl/util/conical_brush.glsl b/src/opengl/util/conical_brush.glsl deleted file mode 100644 index b3ec1d7efe..0000000000 --- a/src/opengl/util/conical_brush.glsl +++ /dev/null @@ -1,27 +0,0 @@ -// conical gradient shader -#define M_PI 3.14159265358979323846 -uniform sampler1D palette; -uniform float angle; -uniform vec3 inv_matrix_m0; -uniform vec3 inv_matrix_m1; -uniform vec3 inv_matrix_m2; - -vec4 brush() -{ - mat3 mat; - - mat[0] = inv_matrix_m0; - mat[1] = inv_matrix_m1; - mat[2] = inv_matrix_m2; - - vec3 hcoords = mat * vec3(gl_FragCoord.xy, 1); - vec2 A = hcoords.xy / hcoords.z; - -/* float val = fmod((atan2(-A.y, A.x) + angle) / (2.0 * M_PI), 1); */ - if (abs(A.y) == abs(A.x)) - A.y += 0.002; - float t = (atan(-A.y, A.x) + angle) / (2.0 * M_PI); - float val = t - floor(t); - return texture1D(palette, val); -} - diff --git a/src/opengl/util/ellipse_aa.glsl b/src/opengl/util/ellipse_aa.glsl deleted file mode 100644 index 257e3bbd47..0000000000 --- a/src/opengl/util/ellipse_aa.glsl +++ /dev/null @@ -1,58 +0,0 @@ -uniform vec3 inv_matrix_m0; -uniform vec3 inv_matrix_m1; -uniform vec3 inv_matrix_m2; - -uniform vec2 ellipse_offset; - -// ellipse equation - -// s^2/a^2 + t^2/b^2 = 1 -// -// implicit equation: -// g(s,t) = 1 - s^2/r_s^2 - t^2/r_t^2 - -// distance from ellipse: -// grad = [dg/dx dg/dy] -// d(s, t) ~= g(s, t) / |grad| - -// dg/dx = dg/ds * ds/dx + dg/dt * dt/dx -// dg/dy = dg/ds * ds/dy + dg/dt * dt/dy - -float ellipse_aa() -{ - mat3 mat; - - mat[0] = inv_matrix_m0; - mat[1] = inv_matrix_m1; - mat[2] = inv_matrix_m2; - - vec3 hcoords = mat * vec3(gl_FragCoord.xy + ellipse_offset, 1); - float inv_w = 1.0 / hcoords.z; - vec2 st = hcoords.xy * inv_w; - - vec4 xy = vec4(mat[0].xy, mat[1].xy); - vec2 h = vec2(mat[0].z, mat[1].z); - - vec4 dstdxy = (xy.xzyw - h.xyxy * st.xxyy) * inv_w; - - //dstdxy.x = (mat[0].x - mat[0].z * st.x) * inv_w; // ds/dx - //dstdxy.y = (mat[1].x - mat[1].z * st.x) * inv_w; // ds/dy - //dstdxy.z = (mat[0].y - mat[0].z * st.y) * inv_w; // dt/dx - //dstdxy.w = (mat[1].y - mat[1].z * st.y) * inv_w; // dt/dy - - vec2 inv_r = gl_TexCoord[0].xy; - vec2 n = st * inv_r; - float g = 1.0 - dot(n, n); - - vec2 dgdst = -2.0 * n * inv_r; - - vec2 grad = vec2(dot(dgdst, dstdxy.xz), - dot(dgdst, dstdxy.yw)); - - return smoothstep(-0.5, 0.5, g * inversesqrt(dot(grad, grad))); -} - -void main() -{ - gl_FragColor = ellipse_aa().xxxx; -} diff --git a/src/opengl/util/fast_painter.glsl b/src/opengl/util/fast_painter.glsl deleted file mode 100644 index 63f5e5f3be..0000000000 --- a/src/opengl/util/fast_painter.glsl +++ /dev/null @@ -1,19 +0,0 @@ -// fast painter for composition modes which can be implemented with blendfuncs - -uniform sampler2D mask_texture; -uniform vec2 inv_mask_size; -uniform vec2 mask_offset; -uniform vec4 mask_channel; - -float mask() -{ - return dot(mask_channel, texture2D(mask_texture, (gl_FragCoord.xy + mask_offset) * inv_mask_size)); -} - -void main() -{ - // combine clip and coverage channels - float mask_alpha = mask(); - - gl_FragColor = brush() * mask_alpha; -} diff --git a/src/opengl/util/fragmentprograms_p.h b/src/opengl/util/fragmentprograms_p.h deleted file mode 100644 index b1a47e3d5f..0000000000 --- a/src/opengl/util/fragmentprograms_p.h +++ /dev/null @@ -1,7287 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef FRAGMENTPROGRAMS_P_H -#define FRAGMENTPROGRAMS_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -enum FragmentVariable { - VAR_BRUSH_TEXTURE, - VAR_LINEAR, - VAR_INV_MATRIX_M1, - VAR_INV_MASK_SIZE, - VAR_INV_MATRIX_M2, - VAR_PORTERDUFF_AB, - VAR_MASK_CHANNEL, - VAR_ELLIPSE_OFFSET, - VAR_PORTERDUFF_XYZ, - VAR_INV_DST_SIZE, - VAR_MASK_TEXTURE, - VAR_DST_TEXTURE, - VAR_PALETTE, - VAR_MASK_OFFSET, - VAR_INV_BRUSH_TEXTURE_SIZE, - VAR_FMP2_M_RADIUS2, - VAR_FMP, - VAR_INV_MATRIX_M0, - VAR_ANGLE -}; - -enum FragmentBrushType { - FRAGMENT_PROGRAM_BRUSH_SOLID, - FRAGMENT_PROGRAM_BRUSH_RADIAL, - FRAGMENT_PROGRAM_BRUSH_CONICAL, - FRAGMENT_PROGRAM_BRUSH_LINEAR, - FRAGMENT_PROGRAM_BRUSH_TEXTURE, - FRAGMENT_PROGRAM_BRUSH_PATTERN -}; - -enum FragmentCompositionModeType { - COMPOSITION_MODES_SIMPLE_PORTER_DUFF, - COMPOSITION_MODES_MULTIPLY, - COMPOSITION_MODES_SCREEN, - COMPOSITION_MODES_OVERLAY, - COMPOSITION_MODES_DARKEN, - COMPOSITION_MODES_LIGHTEN, - COMPOSITION_MODES_COLORDODGE, - COMPOSITION_MODES_COLORBURN, - COMPOSITION_MODES_HARDLIGHT, - COMPOSITION_MODES_SOFTLIGHT, - COMPOSITION_MODES_DIFFERENCE, - COMPOSITION_MODES_EXCLUSION, - COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK, - COMPOSITION_MODES_MULTIPLY_NOMASK, - COMPOSITION_MODES_SCREEN_NOMASK, - COMPOSITION_MODES_OVERLAY_NOMASK, - COMPOSITION_MODES_DARKEN_NOMASK, - COMPOSITION_MODES_LIGHTEN_NOMASK, - COMPOSITION_MODES_COLORDODGE_NOMASK, - COMPOSITION_MODES_COLORBURN_NOMASK, - COMPOSITION_MODES_HARDLIGHT_NOMASK, - COMPOSITION_MODES_SOFTLIGHT_NOMASK, - COMPOSITION_MODES_DIFFERENCE_NOMASK, - COMPOSITION_MODES_EXCLUSION_NOMASK, - COMPOSITION_MODE_BLEND_MODE_MASK, - COMPOSITION_MODE_BLEND_MODE_NOMASK -}; - -enum FragmentMaskType { - FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, - FRAGMENT_PROGRAM_MASK_ELLIPSE_AA -}; - -static const unsigned int num_fragment_variables = 19; - -static const unsigned int num_fragment_brushes = 6; -static const unsigned int num_fragment_composition_modes = 26; -static const unsigned int num_fragment_masks = 2; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA = - "!!ARBfp1.0\n" - "PARAM c[1] = { { 0.5, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "ADD R3.z, fragment.position.x, c[0].x;\n" - "ADD R0.y, fragment.position, -c[0].x;\n" - "MAX R4.x, fragment.texcoord[0].y, R0.y;\n" - "ADD R0.x, fragment.position.y, c[0];\n" - "MIN R3.w, R0.x, fragment.texcoord[0].x;\n" - "ADD R2.z, fragment.position.x, -c[0].x;\n" - "MOV R2.w, R3.z;\n" - "MOV R0.yw, R4.x;\n" - "MOV R0.xz, R3.w;\n" - "MAD R0, fragment.texcoord[1].xxzz, R0, fragment.texcoord[1].yyww;\n" - "MAD R0.zw, fragment.position.x, c[0].y, -R0;\n" - "MOV R2.x, R0;\n" - "MOV R2.y, R0.z;\n" - "MOV R1.w, R0;\n" - "MOV R1.z, R0.y;\n" - "MIN R1.xy, R2, R1.zwzw;\n" - "SGE R0.xy, R1.zwzw, R2;\n" - "ADD R0.zw, -fragment.texcoord[0], -fragment.texcoord[0];\n" - "MAD R3.xy, R0, R0.zwzw, fragment.texcoord[0].zwzw;\n" - "ADD R0, -R1.xxyy, R2.zwzw;\n" - "MAD R0, R0, R3.xxyy, R4.x;\n" - "ADD R3.xy, R0.ywzw, R0.xzzw;\n" - "ADD R4.zw, R3.w, -R0.xyxz;\n" - "ADD R0.zw, -R4.x, R0.xyyw;\n" - "ADD R0.xy, R3.z, -R1;\n" - "MAX R1.zw, R2.xyxy, R1;\n" - "MUL R0.xy, R0, R0.zwzw;\n" - "MAD R3.xy, -R3, c[0].x, R3.w;\n" - "ADD R2.w, R3.z, -R2.z;\n" - "MUL R2.xy, R3, R2.w;\n" - "ADD R2.w, R3, -R4.x;\n" - "ADD R3.xy, -R2.z, R1.zwzw;\n" - "MUL R3.xy, R4.zwzw, R3;\n" - "ADD R4.zw, R1.xyxy, R1;\n" - "MAD R0.zw, R4, c[0].x, -R2.z;\n" - "MAD R0.xy, -R0, c[0].x, R2.w;\n" - "MAD R4.zw, R0, R2.w, -R0.xyxy;\n" - "SGE R0.zw, R3.z, R1;\n" - "MAD R0.xy, R0.zwzw, R4.zwzw, R0;\n" - "MAD R3.xy, R3, c[0].x, -R2;\n" - "MAD R0.zw, R0, R3.xyxy, R2.xyxy;\n" - "ADD R2.xy, R0.zwzw, -R0;\n" - "SGE R0.zw, R2.z, R1.xyxy;\n" - "MAD R0.xy, R0.zwzw, R2, R0;\n" - "SGE R0.zw, R1, R2.z;\n" - "ADD R0.xy, R0, -R2.w;\n" - "SGE R1.xy, R3.z, R1;\n" - "MAD R0.xy, R1, R0, R2.w;\n" - "MAD R0.x, -R0, R0.z, R2.w;\n" - "SGE R0.z, R3.w, R4.x;\n" - "MAD R0.x, -R0.y, R0.w, R0;\n" - "MUL result.color, R0.x, R0.z;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_MASK_ELLIPSE_AA = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..3],\n" - " { -2, 1, -0.5, 2 },\n" - " { 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "ADD R0.xy, fragment.position, c[3];\n" - "MUL R1.xyz, R0.y, c[1];\n" - "MAD R0.xyz, R0.x, c[0], R1;\n" - "ADD R0.xyz, R0, c[2];\n" - "RCP R2.z, R0.z;\n" - "MUL R0.zw, R0.xyxy, R2.z;\n" - "MUL R2.xy, R0.zwzw, fragment.texcoord[0];\n" - "MOV R1.xy, c[0];\n" - "MOV R1.zw, c[1].xyxy;\n" - "MOV R0.x, c[0].z;\n" - "MOV R0.y, c[1].z;\n" - "MAD R0, R0.zzww, -R0.xyxy, R1.xzyw;\n" - "MUL R1.xy, R2, fragment.texcoord[0];\n" - "MUL R0, R2.z, R0;\n" - "MUL R1.xy, R1, c[4].x;\n" - "MUL R1.zw, R1.xyxy, R0.xyxz;\n" - "MUL R0.zw, R1.xyxy, R0.xyyw;\n" - "ADD R0.y, R0.z, R0.w;\n" - "ADD R0.x, R1.z, R1.w;\n" - "MUL R0.xy, R0, R0;\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.zw, R2.xyxy, R2.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "ADD R0.y, -R0.z, c[4];\n" - "RSQ R0.x, R0.x;\n" - "MAD_SAT R0.x, R0, R0.y, -c[4].z;\n" - "MUL R0.y, -R0.x, c[4].w;\n" - "ADD R0.y, R0, c[5].x;\n" - "MUL R0.x, R0, R0;\n" - "MUL result.color, R0.x, R0.y;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SIMPLE_PORTER_DUFF = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xy, fragment.position, c[3];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.xyz, R0, c[0].y;\n" - "MUL R2.xyz, fragment.color.primary.w, R1;\n" - "MUL R1.xyz, fragment.color.primary, c[0].x;\n" - "MAD R2.xyz, R0.w, R1, R2;\n" - "ADD R3.xy, fragment.position, c[4];\n" - "ADD R1.w, -R0, c[6].x;\n" - "MUL R1.xyz, fragment.color.primary, c[1].y;\n" - "MAD R2.xyz, R1.w, R1, R2;\n" - "MUL R1.xyz, R0, c[1].z;\n" - "ADD R2.w, -fragment.color.primary, c[6].x;\n" - "MAD R2.xyz, R2.w, R1, R2;\n" - "MUL R1.z, R0.w, R2.w;\n" - "MUL R1.x, fragment.color.primary.w, R0.w;\n" - "MUL R1.y, fragment.color.primary.w, R1.w;\n" - "DP3 R2.w, R1, c[1];\n" - "MUL R3.xy, R3, c[2];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[5];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_MULTIPLY = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..3],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, -R0.w, c[4];\n" - "MUL R1.xyz, fragment.color.primary, R1.x;\n" - "MAD R1.xyz, fragment.color.primary, R0, R1;\n" - "ADD R1.w, -fragment.color.primary, c[4].x;\n" - "MAD R2.xyz, R0, R1.w, R1;\n" - "ADD R1.z, fragment.color.primary.w, R0.w;\n" - "MAD R2.w, -fragment.color.primary, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[2];\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[3];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SCREEN = - "!!ARBfp1.0\n" - "PARAM c[4] = { program.local[0..3] };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.xy, fragment.position, c[2];\n" - "ADD R2, fragment.color.primary, R0;\n" - "MUL R1.xy, R1, c[0];\n" - "MAD R2, -fragment.color.primary, R0, R2;\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[3];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_OVERLAY = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..3],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R1, R0, texture[0], 2D;\n" - "ADD R0.w, -R1, c[4].y;\n" - "MUL R3.xyz, fragment.color.primary, R0.w;\n" - "ADD R2.xyz, fragment.color.primary.w, -fragment.color.primary;\n" - "ADD R0.xyz, R1.w, -R1;\n" - "MUL R0.xyz, R0, R2;\n" - "MUL R0.xyz, R0, c[4].x;\n" - "MAD R0.xyz, fragment.color.primary.w, R1.w, -R0;\n" - "MAD R0.xyz, fragment.color.primary, R0.w, R0;\n" - "MUL R2.xyz, fragment.color.primary, R1;\n" - "MAD R2.xyz, R2, c[4].x, R3;\n" - "ADD R0.w, -fragment.color.primary, c[4].y;\n" - "MAD R3.xyz, R1, R0.w, R0;\n" - "MAD R2.xyz, R1, R0.w, R2;\n" - "MUL R0.xyz, R1, c[4].x;\n" - "SGE R0.xyz, R0, R1.w;\n" - "ADD R3.xyz, R3, -R2;\n" - "MAD R2.xyz, R0, R3, R2;\n" - "ADD R0.z, fragment.color.primary.w, R1.w;\n" - "MAD R2.w, -fragment.color.primary, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[2];\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[3];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_DARKEN = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..3],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R2.xyz, fragment.color.primary.w, R0;\n" - "MUL R1.xyz, fragment.color.primary, R0.w;\n" - "MIN R1.xyz, R1, R2;\n" - "ADD R1.w, -R0, c[4].x;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n" - "ADD R1.w, -fragment.color.primary, c[4].x;\n" - "MAD R2.xyz, R0, R1.w, R1;\n" - "ADD R1.z, fragment.color.primary.w, R0.w;\n" - "MAD R2.w, -fragment.color.primary, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[2];\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[3];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_LIGHTEN = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..3],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R2.xyz, fragment.color.primary.w, R0;\n" - "MUL R1.xyz, fragment.color.primary, R0.w;\n" - "MAX R1.xyz, R1, R2;\n" - "ADD R1.w, -R0, c[4].x;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n" - "ADD R1.w, -fragment.color.primary, c[4].x;\n" - "MAD R2.xyz, R0, R1.w, R1;\n" - "ADD R1.z, fragment.color.primary.w, R0.w;\n" - "MAD R2.w, -fragment.color.primary, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[2];\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[3];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORDODGE = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..3],\n" - " { 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, -fragment.color.primary.w, c[4];\n" - "MAX R1.y, fragment.color.primary.w, c[4];\n" - "MUL R2.xyz, R0, R1.x;\n" - "ADD R1.w, -R0, c[4].x;\n" - "MAD R3.xyz, fragment.color.primary, R1.w, R2;\n" - "RCP R1.y, R1.y;\n" - "MAD R1.xyz, -fragment.color.primary, R1.y, c[4].x;\n" - "MAX R1.xyz, R1, c[4].y;\n" - "MUL R2.xyz, fragment.color.primary.w, R0;\n" - "MUL R1.w, fragment.color.primary, R0;\n" - "RCP R1.x, R1.x;\n" - "RCP R1.y, R1.y;\n" - "RCP R1.z, R1.z;\n" - "MAD R1.xyz, R2, R1, R3;\n" - "MAD R3.xyz, fragment.color.primary.w, R0.w, R3;\n" - "MAD R2.xyz, fragment.color.primary, R0.w, R2;\n" - "ADD R3.xyz, R3, -R1;\n" - "SGE R2.xyz, R2, R1.w;\n" - "MAD R2.xyz, R2, R3, R1;\n" - "ADD R1.z, fragment.color.primary.w, R0.w;\n" - "MAD R2.w, -fragment.color.primary, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[2];\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[3];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORBURN = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..3],\n" - " { 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.w, -R0, c[4].x;\n" - "MUL R1.xyz, fragment.color.primary.w, R0;\n" - "MAD R2.xyz, fragment.color.primary, R0.w, R1;\n" - "MAD R1.xyz, -fragment.color.primary.w, R0.w, R2;\n" - "MUL R3.xyz, fragment.color.primary.w, R1;\n" - "MAX R1.xyz, fragment.color.primary, c[4].y;\n" - "ADD R2.w, -fragment.color.primary, c[4].x;\n" - "MUL R4.xyz, fragment.color.primary, R1.w;\n" - "RCP R1.x, R1.x;\n" - "RCP R1.y, R1.y;\n" - "RCP R1.z, R1.z;\n" - "MAD R3.xyz, R3, R1, R4;\n" - "MUL R1.xyz, R0, R2.w;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n" - "MAD R3.xyz, R0, R2.w, R3;\n" - "MUL R1.w, fragment.color.primary, R0;\n" - "ADD R3.xyz, R3, -R1;\n" - "SGE R2.xyz, R2, R1.w;\n" - "MAD R2.xyz, R2, R3, R1;\n" - "ADD R1.z, fragment.color.primary.w, R0.w;\n" - "MAD R2.w, -fragment.color.primary, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[2];\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[3];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_HARDLIGHT = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..3],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R1, R0, texture[0], 2D;\n" - "ADD R0.w, -R1, c[4].y;\n" - "MUL R3.xyz, fragment.color.primary, R0.w;\n" - "ADD R2.xyz, fragment.color.primary.w, -fragment.color.primary;\n" - "ADD R0.xyz, R1.w, -R1;\n" - "MUL R0.xyz, R0, R2;\n" - "MUL R0.xyz, R0, c[4].x;\n" - "MAD R0.xyz, fragment.color.primary.w, R1.w, -R0;\n" - "MAD R0.xyz, fragment.color.primary, R0.w, R0;\n" - "MUL R2.xyz, fragment.color.primary, R1;\n" - "MAD R2.xyz, R2, c[4].x, R3;\n" - "ADD R0.w, -fragment.color.primary, c[4].y;\n" - "MAD R3.xyz, R1, R0.w, R0;\n" - "MAD R2.xyz, R1, R0.w, R2;\n" - "MUL R0.xyz, fragment.color.primary, c[4].x;\n" - "SGE R0.xyz, R0, fragment.color.primary.w;\n" - "ADD R3.xyz, R3, -R2;\n" - "MAD R2.xyz, R0, R3, R2;\n" - "ADD R0.z, fragment.color.primary.w, R1.w;\n" - "MAD R2.w, -fragment.color.primary, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[2];\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[3];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SOFTLIGHT = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..3],\n" - " { 1, 2, 9.9999997e-006, 4 },\n" - " { 16, 12, 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MAX R1.x, R0.w, c[4].z;\n" - "RCP R1.x, R1.x;\n" - "MUL R2.xyz, R0, R1.x;\n" - "MAD R1.xyz, R2, c[5].x, -c[5].y;\n" - "MAD R3.xyz, R2, R1, c[5].z;\n" - "MAD R1.xyz, fragment.color.primary, c[4].y, -fragment.color.primary.w;\n" - "MUL R4.xyz, R0.w, R1;\n" - "MUL R5.xyz, R4, R3;\n" - "RSQ R1.w, R2.x;\n" - "RSQ R2.w, R2.z;\n" - "RCP R3.x, R1.w;\n" - "RSQ R1.w, R2.y;\n" - "MUL R5.xyz, R2, R5;\n" - "RCP R3.z, R2.w;\n" - "RCP R3.y, R1.w;\n" - "ADD R3.xyz, -R2, R3;\n" - "MUL R3.xyz, R4, R3;\n" - "ADD R2.xyz, -R2, c[4].x;\n" - "MAD R1.xyz, R1, R2, fragment.color.primary.w;\n" - "MUL R2.xyz, fragment.color.primary, c[4].y;\n" - "MAD R4.xyz, fragment.color.primary.w, R0, R5;\n" - "MAD R3.xyz, fragment.color.primary.w, R0, R3;\n" - "ADD R5.xyz, R3, -R4;\n" - "MUL R3.xyz, R0, c[4].w;\n" - "SGE R3.xyz, R3, R0.w;\n" - "MAD R3.xyz, R3, R5, R4;\n" - "MAD R3.xyz, -R0, R1, R3;\n" - "MUL R1.xyz, R0, R1;\n" - "SGE R2.xyz, R2, fragment.color.primary.w;\n" - "MAD R2.xyz, R2, R3, R1;\n" - "ADD R1.x, -R0.w, c[4];\n" - "MAD R2.xyz, fragment.color.primary, R1.x, R2;\n" - "ADD R1.x, -fragment.color.primary.w, c[4];\n" - "MAD R2.xyz, R0, R1.x, R2;\n" - "ADD R1.z, fragment.color.primary.w, R0.w;\n" - "MAD R2.w, -fragment.color.primary, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[2];\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[3];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_DIFFERENCE = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..3],\n" - " { 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.xyz, fragment.color.primary, R0;\n" - "MUL R3.xyz, fragment.color.primary.w, R0;\n" - "MUL R2.xyz, fragment.color.primary, R0.w;\n" - "MIN R2.xyz, R2, R3;\n" - "MAD R2.xyz, -R2, c[4].x, R1;\n" - "ADD R1.z, fragment.color.primary.w, R0.w;\n" - "MAD R2.w, -fragment.color.primary, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[2];\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[3];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_EXCLUSION = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..3],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[1];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.xyz, fragment.color.primary.w, R0;\n" - "MAD R2.xyz, fragment.color.primary, R0.w, R1;\n" - "MUL R1.xyz, fragment.color.primary, R0;\n" - "MAD R1.xyz, -R1, c[4].x, R2;\n" - "ADD R1.w, -R0, c[4].y;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n" - "ADD R1.w, -fragment.color.primary, c[4].y;\n" - "MAD R2.xyz, R0, R1.w, R1;\n" - "ADD R1.z, fragment.color.primary.w, R0.w;\n" - "MAD R2.w, -fragment.color.primary, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[2];\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[3];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[4] = { program.local[0..2],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[2];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.xyz, R0, c[0].y;\n" - "MUL R2.xyz, fragment.color.primary.w, R1;\n" - "MUL R1.xyz, fragment.color.primary, c[0].x;\n" - "MAD R2.xyz, R0.w, R1, R2;\n" - "MUL R0.xyz, R0, c[1].z;\n" - "ADD R1.w, -R0, c[3].x;\n" - "MUL R1.xyz, fragment.color.primary, c[1].y;\n" - "MAD R1.xyz, R1.w, R1, R2;\n" - "ADD R2.x, -fragment.color.primary.w, c[3];\n" - "MAD result.color.xyz, R2.x, R0, R1;\n" - "MUL R0.x, fragment.color.primary.w, R0.w;\n" - "MUL R0.z, R0.w, R2.x;\n" - "MUL R0.y, fragment.color.primary.w, R1.w;\n" - "DP3 result.color.w, R0, c[1];\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_MULTIPLY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[2] = { program.local[0],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, -R0.w, c[1];\n" - "MUL R1.xyz, fragment.color.primary, R1.x;\n" - "ADD R1.w, fragment.color.primary, R0;\n" - "MAD R1.xyz, fragment.color.primary, R0, R1;\n" - "ADD R2.x, -fragment.color.primary.w, c[1];\n" - "MAD result.color.xyz, R0, R2.x, R1;\n" - "MAD result.color.w, -fragment.color.primary, R0, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SCREEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[1] = { program.local[0] };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1, fragment.color.primary, R0;\n" - "MAD result.color, -fragment.color.primary, R0, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_OVERLAY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[2] = { program.local[0],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.w, -R0, c[1].y;\n" - "ADD R2.xyz, fragment.color.primary.w, -fragment.color.primary;\n" - "ADD R1.xyz, R0.w, -R0;\n" - "MUL R1.xyz, R1, R2;\n" - "MUL R1.xyz, R1, c[1].x;\n" - "MAD R1.xyz, fragment.color.primary.w, R0.w, -R1;\n" - "MUL R3.xyz, fragment.color.primary, R1.w;\n" - "MUL R2.xyz, fragment.color.primary, R0;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n" - "ADD R1.w, -fragment.color.primary, c[1].y;\n" - "MAD R2.xyz, R2, c[1].x, R3;\n" - "MAD R2.xyz, R0, R1.w, R2;\n" - "MAD R1.xyz, R0, R1.w, R1;\n" - "MUL R0.xyz, R0, c[1].x;\n" - "ADD R1.w, fragment.color.primary, R0;\n" - "ADD R1.xyz, R1, -R2;\n" - "SGE R0.xyz, R0, R0.w;\n" - "MAD result.color.xyz, R0, R1, R2;\n" - "MAD result.color.w, -fragment.color.primary, R0, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_DARKEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[2] = { program.local[0],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R2.xyz, fragment.color.primary.w, R0;\n" - "MUL R1.xyz, fragment.color.primary, R0.w;\n" - "MIN R1.xyz, R1, R2;\n" - "ADD R1.w, -R0, c[1].x;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n" - "ADD R1.w, fragment.color.primary, R0;\n" - "ADD R2.x, -fragment.color.primary.w, c[1];\n" - "MAD result.color.xyz, R0, R2.x, R1;\n" - "MAD result.color.w, -fragment.color.primary, R0, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_LIGHTEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[2] = { program.local[0],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R2.xyz, fragment.color.primary.w, R0;\n" - "MUL R1.xyz, fragment.color.primary, R0.w;\n" - "MAX R1.xyz, R1, R2;\n" - "ADD R1.w, -R0, c[1].x;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n" - "ADD R1.w, fragment.color.primary, R0;\n" - "ADD R2.x, -fragment.color.primary.w, c[1];\n" - "MAD result.color.xyz, R0, R2.x, R1;\n" - "MAD result.color.w, -fragment.color.primary, R0, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORDODGE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[2] = { program.local[0],\n" - " { 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MAX R1.y, fragment.color.primary.w, c[1];\n" - "RCP R2.x, R1.y;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, -fragment.color.primary.w, c[1];\n" - "MUL R1.xyz, R0, R1.x;\n" - "ADD R1.w, -R0, c[1].x;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n" - "MAD R2.xyz, -fragment.color.primary, R2.x, c[1].x;\n" - "MAX R2.xyz, R2, c[1].y;\n" - "MUL R0.xyz, fragment.color.primary.w, R0;\n" - "MUL R1.w, fragment.color.primary, R0;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R0, R2, R1;\n" - "MAD R1.xyz, fragment.color.primary.w, R0.w, R1;\n" - "MAD R0.xyz, fragment.color.primary, R0.w, R0;\n" - "SGE R0.xyz, R0, R1.w;\n" - "ADD R1.xyz, R1, -R2;\n" - "ADD R1.w, fragment.color.primary, R0;\n" - "MAD result.color.xyz, R0, R1, R2;\n" - "MAD result.color.w, -fragment.color.primary, R0, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORBURN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[2] = { program.local[0],\n" - " { 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.xyz, fragment.color.primary.w, R0;\n" - "MAD R2.xyz, fragment.color.primary, R0.w, R1;\n" - "MAD R1.xyz, -fragment.color.primary.w, R0.w, R2;\n" - "MUL R3.xyz, fragment.color.primary.w, R1;\n" - "MAX R1.xyz, fragment.color.primary, c[1].y;\n" - "ADD R1.w, -R0, c[1].x;\n" - "MUL R4.xyz, fragment.color.primary, R1.w;\n" - "ADD R2.w, -fragment.color.primary, c[1].x;\n" - "RCP R1.x, R1.x;\n" - "RCP R1.y, R1.y;\n" - "RCP R1.z, R1.z;\n" - "MAD R1.xyz, R3, R1, R4;\n" - "MUL R3.xyz, R0, R2.w;\n" - "MAD R0.xyz, R0, R2.w, R1;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R3;\n" - "MUL R1.w, fragment.color.primary, R0;\n" - "SGE R2.xyz, R2, R1.w;\n" - "ADD R0.xyz, R0, -R1;\n" - "ADD R1.w, fragment.color.primary, R0;\n" - "MAD result.color.xyz, R2, R0, R1;\n" - "MAD result.color.w, -fragment.color.primary, R0, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_HARDLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[2] = { program.local[0],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.w, -R0, c[1].y;\n" - "ADD R2.xyz, fragment.color.primary.w, -fragment.color.primary;\n" - "ADD R1.xyz, R0.w, -R0;\n" - "MUL R1.xyz, R1, R2;\n" - "MUL R1.xyz, R1, c[1].x;\n" - "MAD R1.xyz, fragment.color.primary.w, R0.w, -R1;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n" - "MUL R3.xyz, fragment.color.primary, R1.w;\n" - "MUL R2.xyz, fragment.color.primary, R0;\n" - "ADD R1.w, -fragment.color.primary, c[1].y;\n" - "MAD R2.xyz, R2, c[1].x, R3;\n" - "MAD R2.xyz, R0, R1.w, R2;\n" - "MAD R0.xyz, R0, R1.w, R1;\n" - "ADD R1.xyz, R0, -R2;\n" - "MUL R0.xyz, fragment.color.primary, c[1].x;\n" - "ADD R1.w, fragment.color.primary, R0;\n" - "SGE R0.xyz, R0, fragment.color.primary.w;\n" - "MAD result.color.xyz, R0, R1, R2;\n" - "MAD result.color.w, -fragment.color.primary, R0, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SOFTLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[3] = { program.local[0],\n" - " { 1, 2, 9.9999997e-006, 4 },\n" - " { 16, 12, 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MAX R1.x, R0.w, c[1].z;\n" - "RCP R1.x, R1.x;\n" - "MUL R2.xyz, R0, R1.x;\n" - "MAD R1.xyz, R2, c[2].x, -c[2].y;\n" - "MAD R3.xyz, R2, R1, c[2].z;\n" - "MAD R1.xyz, fragment.color.primary, c[1].y, -fragment.color.primary.w;\n" - "MUL R4.xyz, R0.w, R1;\n" - "MUL R5.xyz, R4, R3;\n" - "RSQ R1.w, R2.x;\n" - "RCP R3.x, R1.w;\n" - "RSQ R2.w, R2.z;\n" - "RSQ R1.w, R2.y;\n" - "MUL R5.xyz, R2, R5;\n" - "RCP R3.z, R2.w;\n" - "RCP R3.y, R1.w;\n" - "ADD R3.xyz, -R2, R3;\n" - "MUL R3.xyz, R4, R3;\n" - "ADD R2.xyz, -R2, c[1].x;\n" - "MAD R1.xyz, R1, R2, fragment.color.primary.w;\n" - "MUL R2.xyz, fragment.color.primary, c[1].y;\n" - "MAD R4.xyz, fragment.color.primary.w, R0, R5;\n" - "MAD R3.xyz, fragment.color.primary.w, R0, R3;\n" - "ADD R5.xyz, R3, -R4;\n" - "MUL R3.xyz, R0, c[1].w;\n" - "SGE R3.xyz, R3, R0.w;\n" - "MAD R3.xyz, R3, R5, R4;\n" - "MAD R3.xyz, -R0, R1, R3;\n" - "MUL R1.xyz, R0, R1;\n" - "SGE R2.xyz, R2, fragment.color.primary.w;\n" - "MAD R2.xyz, R2, R3, R1;\n" - "ADD R1.x, -R0.w, c[1];\n" - "MAD R2.xyz, fragment.color.primary, R1.x, R2;\n" - "ADD R1.x, fragment.color.primary.w, R0.w;\n" - "ADD R1.y, -fragment.color.primary.w, c[1].x;\n" - "MAD result.color.xyz, R0, R1.y, R2;\n" - "MAD result.color.w, -fragment.color.primary, R0, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_DIFFERENCE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[2] = { program.local[0],\n" - " { 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R2.xyz, fragment.color.primary.w, R0;\n" - "MUL R1.xyz, fragment.color.primary, R0.w;\n" - "ADD R1.w, fragment.color.primary, R0;\n" - "MIN R1.xyz, R1, R2;\n" - "ADD R0.xyz, fragment.color.primary, R0;\n" - "MAD result.color.xyz, -R1, c[1].x, R0;\n" - "MAD result.color.w, -fragment.color.primary, R0, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_EXCLUSION_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[2] = { program.local[0],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xy, fragment.position, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.xyz, fragment.color.primary.w, R0;\n" - "MAD R2.xyz, fragment.color.primary, R0.w, R1;\n" - "MUL R1.xyz, fragment.color.primary, R0;\n" - "MAD R1.xyz, -R1, c[1].x, R2;\n" - "ADD R1.w, -R0, c[1].y;\n" - "MAD R1.xyz, fragment.color.primary, R1.w, R1;\n" - "ADD R1.w, fragment.color.primary, R0;\n" - "ADD R2.x, -fragment.color.primary.w, c[1].y;\n" - "MAD result.color.xyz, R0, R2.x, R1;\n" - "MAD result.color.w, -fragment.color.primary, R0, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE_BLEND_MODE_MASK = - "!!ARBfp1.0\n" - "PARAM c[3] = { program.local[0..2] };\n" - "TEMP R0;\n" - "ADD R0.xy, fragment.position, c[1];\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[0], 2D;\n" - "DP4 R0.x, R0, c[2];\n" - "MUL result.color, fragment.color.primary, R0.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE_BLEND_MODE_NOMASK = - "!!ARBfp1.0\n" - "MOV result.color, fragment.color.primary;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF = - "!!ARBfp1.0\n" - "PARAM c[12] = { program.local[0..10],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[11].x;\n" - "MUL R0.z, R0, c[11].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.x, R0.x;\n" - "RCP R0.z, R0.x;\n" - "ADD R1.x, -R0.y, R0.z;\n" - "MOV R0.x, c[11];\n" - "MUL R0.z, R0.x, c[1].x;\n" - "RCP R1.y, R0.z;\n" - "MUL R0.xy, fragment.position, c[8];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.x, R1, R1.y;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R2.xyz, R0, c[5].y;\n" - "MUL R3.xyz, R1.w, R2;\n" - "MUL R2.xyz, R1, c[5].x;\n" - "MAD R2.xyz, R0.w, R2, R3;\n" - "ADD R3.xy, fragment.position, c[9];\n" - "ADD R2.w, -R0, c[11].z;\n" - "MUL R1.xyz, R1, c[6].y;\n" - "MAD R2.xyz, R2.w, R1, R2;\n" - "MUL R1.xyz, R0, c[6].z;\n" - "ADD R3.z, -R1.w, c[11];\n" - "MAD R2.xyz, R3.z, R1, R2;\n" - "MUL R1.y, R1.w, R2.w;\n" - "MUL R1.x, R1.w, R0.w;\n" - "MUL R1.z, R0.w, R3;\n" - "DP3 R2.w, R1, c[6];\n" - "MUL R3.xy, R3, c[7];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[10];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_MULTIPLY = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..8],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.x, R0.x;\n" - "RCP R0.z, R0.x;\n" - "ADD R1.x, -R0.y, R0.z;\n" - "MOV R0.x, c[9];\n" - "MUL R0.z, R0.x, c[1].x;\n" - "RCP R1.y, R0.z;\n" - "MUL R0.xy, fragment.position, c[6];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.x, R1, R1.y;\n" - "TEX R1, R1, texture[2], 1D;\n" - "ADD R2.x, -R0.w, c[9].z;\n" - "MUL R2.xyz, R1, R2.x;\n" - "MAD R1.xyz, R1, R0, R2;\n" - "ADD R2.x, -R1.w, c[9].z;\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[7];\n" - "MUL R1.xy, R1, c[5];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[8];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SCREEN = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..8],\n" - " { 2, 4 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MOV R0.x, c[9];\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.z, R0.y, R0.y, -R0;\n" - "ADD R3.xy, fragment.position, c[7];\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RSQ R0.z, R0.z;\n" - "RCP R0.x, R0.z;\n" - "RCP R0.z, R0.w;\n" - "ADD R0.x, -R0.y, R0;\n" - "MUL R0.z, R0.x, R0;\n" - "TEX R1, R0.z, texture[2], 1D;\n" - "MUL R0.xy, fragment.position, c[6];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R2, R1, R0;\n" - "MAD R2, -R1, R0, R2;\n" - "MUL R3.xy, R3, c[5];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[8];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_OVERLAY = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..8],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MOV R0.x, c[9];\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.z, R0.y, R0.y, -R0;\n" - "MUL R1.xy, fragment.position, c[6];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RSQ R0.z, R0.z;\n" - "RCP R0.x, R0.z;\n" - "ADD R2.w, -R1, c[9].z;\n" - "RCP R0.z, R0.w;\n" - "ADD R0.x, -R0.y, R0;\n" - "MUL R0.x, R0, R0.z;\n" - "TEX R0, R0, texture[2], 1D;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[9].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MUL R3.xyz, R0, R1;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, -R0.w, c[9].z;\n" - "MAD R3.xyz, R3, c[9].x, R4;\n" - "MAD R3.xyz, R1, R2.x, R3;\n" - "MAD R0.xyz, R1, R2.x, R0;\n" - "MUL R2.xyz, R1, c[9].x;\n" - "ADD R0.xyz, R0, -R3;\n" - "SGE R2.xyz, R2, R1.w;\n" - "MAD R2.xyz, R2, R0, R3;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[7];\n" - "MUL R0.xy, R0, c[5];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[8];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DARKEN = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..8],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[9];\n" - "MUL R0.x, R0, c[1];\n" - "RCP R0.z, R0.z;\n" - "ADD R0.z, -R0.y, R0;\n" - "RCP R0.w, R0.x;\n" - "MUL R1.x, R0.z, R0.w;\n" - "MUL R0.xy, fragment.position, c[6];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[9].z;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[9].z;\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[7];\n" - "MUL R1.xy, R1, c[5];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[8];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_LIGHTEN = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..8],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[9];\n" - "MUL R0.x, R0, c[1];\n" - "RCP R0.z, R0.z;\n" - "ADD R0.z, -R0.y, R0;\n" - "RCP R0.w, R0.x;\n" - "MUL R1.x, R0.z, R0.w;\n" - "MUL R0.xy, fragment.position, c[6];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MAX R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[9].z;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[9].z;\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[7];\n" - "MUL R1.xy, R1, c[5];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[8];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORDODGE = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..8],\n" - " { 2, 4, 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MOV R0.x, c[9];\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.z, R0.y, R0.y, -R0;\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RSQ R0.z, R0.z;\n" - "RCP R0.x, R0.z;\n" - "RCP R0.z, R0.w;\n" - "ADD R0.x, -R0.y, R0;\n" - "MUL R0.x, R0, R0.z;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MAX R1.x, R0.w, c[9].w;\n" - "RCP R1.x, R1.x;\n" - "MAD R1.xyz, -R0, R1.x, c[9].z;\n" - "MAX R2.xyz, R1, c[9].w;\n" - "MUL R1.xy, fragment.position, c[6];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R0, c[9].z;\n" - "MUL R3.xyz, R1, R2.w;\n" - "ADD R2.w, -R1, c[9].z;\n" - "MAD R4.xyz, R0, R2.w, R3;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MUL R2.w, R0, R1;\n" - "MAD R0.xyz, R0, R1.w, R3;\n" - "SGE R0.xyz, R0, R2.w;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R3, R2, R4;\n" - "MAD R4.xyz, R0.w, R1.w, R4;\n" - "ADD R4.xyz, R4, -R2;\n" - "MAD R2.xyz, R0, R4, R2;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[7];\n" - "MUL R0.xy, R0, c[5];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[8];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORBURN = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..8],\n" - " { 2, 4, 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[9];\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RCP R0.z, R0.z;\n" - "ADD R0.x, -R0.y, R0.z;\n" - "RCP R0.y, R0.w;\n" - "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, R0.y;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "MAD R2.xyz, -R0.w, R1.w, R3;\n" - "MUL R4.xyz, R0.w, R2;\n" - "MAX R2.xyz, R0, c[9].w;\n" - "ADD R2.w, -R1, c[9].z;\n" - "MUL R5.xyz, R0, R2.w;\n" - "ADD R3.w, -R0, c[9].z;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R4, R2, R5;\n" - "MUL R4.xyz, R1, R3.w;\n" - "MAD R0.xyz, R0, R2.w, R4;\n" - "MUL R2.w, R0, R1;\n" - "MAD R2.xyz, R1, R3.w, R2;\n" - "ADD R2.xyz, R2, -R0;\n" - "SGE R3.xyz, R3, R2.w;\n" - "MAD R2.xyz, R3, R2, R0;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[7];\n" - "MUL R0.xy, R0, c[5];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[8];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_HARDLIGHT = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..8],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MOV R0.x, c[9];\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.z, R0.y, R0.y, -R0;\n" - "MUL R1.xy, fragment.position, c[6];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RSQ R0.z, R0.z;\n" - "RCP R0.x, R0.z;\n" - "ADD R2.w, -R1, c[9].z;\n" - "RCP R0.z, R0.w;\n" - "ADD R0.x, -R0.y, R0;\n" - "MUL R0.x, R0, R0.z;\n" - "TEX R0, R0, texture[2], 1D;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[9].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R3.xyz, R0, R1;\n" - "ADD R2.w, -R0, c[9].z;\n" - "MAD R3.xyz, R3, c[9].x, R4;\n" - "MUL R0.xyz, R0, c[9].x;\n" - "SGE R0.xyz, R0, R0.w;\n" - "MAD R3.xyz, R1, R2.w, R3;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "ADD R2.xyz, R2, -R3;\n" - "MAD R2.xyz, R0, R2, R3;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[7];\n" - "MUL R0.xy, R0, c[5];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[8];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SOFTLIGHT = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..8],\n" - " { 2, 4, 1, 9.9999997e-006 },\n" - " { 16, 12, 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "TEMP R6;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.z, c[9];\n" - "MUL R0.x, R0, c[9];\n" - "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MAD R0.y, R0.x, R0.x, -R0;\n" - "RSQ R0.y, R0.y;\n" - "RCP R0.y, R0.y;\n" - "ADD R0.y, -R0.x, R0;\n" - "MOV R0.x, c[9];\n" - "MUL R0.x, R0, c[1];\n" - "MAX R0.z, R1.w, c[9].w;\n" - "RCP R0.z, R0.z;\n" - "MUL R3.xyz, R1, R0.z;\n" - "MAD R4.xyz, R3, c[10].x, -c[10].y;\n" - "RCP R0.x, R0.x;\n" - "MUL R0.x, R0.y, R0;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MAD R2.xyz, R0, c[9].x, -R0.w;\n" - "MAD R4.xyz, R3, R4, c[10].z;\n" - "MUL R5.xyz, R1.w, R2;\n" - "MUL R6.xyz, R5, R4;\n" - "RSQ R2.w, R3.x;\n" - "RCP R4.x, R2.w;\n" - "RSQ R2.w, R3.y;\n" - "RSQ R3.w, R3.z;\n" - "RCP R4.y, R2.w;\n" - "RCP R4.z, R3.w;\n" - "ADD R4.xyz, -R3, R4;\n" - "MUL R6.xyz, R3, R6;\n" - "MUL R4.xyz, R5, R4;\n" - "ADD R3.xyz, -R3, c[9].z;\n" - "MAD R2.xyz, R2, R3, R0.w;\n" - "MUL R3.xyz, R0, c[9].x;\n" - "MAD R5.xyz, R0.w, R1, R6;\n" - "MAD R4.xyz, R0.w, R1, R4;\n" - "ADD R6.xyz, R4, -R5;\n" - "MUL R4.xyz, R1, c[9].y;\n" - "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R6, R5;\n" - "MAD R4.xyz, -R1, R2, R4;\n" - "SGE R3.xyz, R3, R0.w;\n" - "MUL R2.xyz, R1, R2;\n" - "ADD R2.w, -R1, c[9].z;\n" - "MAD R2.xyz, R3, R4, R2;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R0.x, -R0.w, c[9].z;\n" - "MAD R2.xyz, R1, R0.x, R2;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[7];\n" - "MUL R0.xy, R0, c[5];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[8];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DIFFERENCE = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..8],\n" - " { 2, 4 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[9];\n" - "MUL R0.x, R0, c[1];\n" - "RCP R0.z, R0.z;\n" - "ADD R0.z, -R0.y, R0;\n" - "RCP R0.w, R0.x;\n" - "MUL R1.x, R0.z, R0.w;\n" - "MUL R0.xy, fragment.position, c[6];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "ADD R2.xyz, R1, R0;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R1.xyz, R1, R0.w;\n" - "MIN R1.xyz, R1, R3;\n" - "MAD R2.xyz, -R1, c[9].x, R2;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[7];\n" - "MUL R1.xy, R1, c[5];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[8];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_EXCLUSION = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..8],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[9].x;\n" - "MUL R0.z, R0, c[9].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[9];\n" - "MUL R0.x, R0, c[1];\n" - "RCP R0.z, R0.z;\n" - "ADD R0.z, -R0.y, R0;\n" - "RCP R0.w, R0.x;\n" - "MUL R1.x, R0.z, R0.w;\n" - "MUL R0.xy, fragment.position, c[6];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R2.xyz, R1.w, R0;\n" - "MAD R3.xyz, R1, R0.w, R2;\n" - "MUL R2.xyz, R1, R0;\n" - "MAD R2.xyz, -R2, c[9].x, R3;\n" - "ADD R2.w, -R0, c[9].z;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[9].z;\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[7];\n" - "MUL R1.xy, R1, c[5];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[8];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[8].x;\n" - "MUL R0.z, R0, c[8].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.x, R0.x;\n" - "RCP R0.z, R0.x;\n" - "ADD R0.y, -R0, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R2.xyz, R1, c[5].y;\n" - "MOV R0.x, c[8];\n" - "MUL R0.x, R0, c[1];\n" - "RCP R0.x, R0.x;\n" - "MUL R0.x, R0.y, R0;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R3.xyz, R0.w, R2;\n" - "MUL R2.xyz, R0, c[5].x;\n" - "MAD R2.xyz, R1.w, R2, R3;\n" - "ADD R2.w, -R1, c[8].z;\n" - "MUL R0.xyz, R0, c[6].y;\n" - "MAD R0.xyz, R2.w, R0, R2;\n" - "ADD R2.x, -R0.w, c[8].z;\n" - "MUL R1.xyz, R1, c[6].z;\n" - "MAD result.color.xyz, R2.x, R1, R0;\n" - "MUL R0.x, R0.w, R1.w;\n" - "MUL R0.z, R1.w, R2.x;\n" - "MUL R0.y, R0.w, R2.w;\n" - "DP3 result.color.w, R0, c[6];\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_MULTIPLY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.x, R0.x;\n" - "RCP R0.z, R0.x;\n" - "ADD R0.y, -R0, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MOV R0.x, c[6];\n" - "MUL R0.x, R0, c[1];\n" - "RCP R0.x, R0.x;\n" - "MUL R0.x, R0.y, R0;\n" - "TEX R0, R0, texture[1], 1D;\n" - "ADD R2.x, -R1.w, c[6].z;\n" - "MUL R2.xyz, R0, R2.x;\n" - "MAD R0.xyz, R0, R1, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[6].z;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SCREEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 2, 4 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[6];\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RCP R0.z, R0.z;\n" - "ADD R0.x, -R0.y, R0.z;\n" - "RCP R0.y, R0.w;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "ADD R2, R0, R1;\n" - "MAD result.color, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_OVERLAY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MOV R0.x, c[6];\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.z, R0.y, R0.y, -R0;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RSQ R0.z, R0.z;\n" - "RCP R0.x, R0.z;\n" - "ADD R2.w, -R1, c[6].z;\n" - "RCP R0.z, R0.w;\n" - "ADD R0.x, -R0.y, R0;\n" - "MUL R0.x, R0, R0.z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[6].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R3.xyz, R0, R2.w;\n" - "MUL R0.xyz, R0, R1;\n" - "ADD R2.w, -R0, c[6].z;\n" - "MAD R0.xyz, R0, c[6].x, R3;\n" - "MAD R0.xyz, R1, R2.w, R0;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "MUL R1.xyz, R1, c[6].x;\n" - "ADD R2.w, R0, R1;\n" - "ADD R2.xyz, R2, -R0;\n" - "SGE R1.xyz, R1, R1.w;\n" - "MAD result.color.xyz, R1, R2, R0;\n" - "MAD result.color.w, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DARKEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[6];\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RCP R0.z, R0.z;\n" - "ADD R0.x, -R0.y, R0.z;\n" - "RCP R0.y, R0.w;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[6].z;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[6].z;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_LIGHTEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[6];\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RCP R0.z, R0.z;\n" - "ADD R0.x, -R0.y, R0.z;\n" - "RCP R0.y, R0.w;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MAX R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[6].z;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[6].z;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORDODGE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 2, 4, 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MOV R0.x, c[6];\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.z, R0.y, R0.y, -R0;\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RSQ R0.z, R0.z;\n" - "RCP R0.x, R0.z;\n" - "RCP R0.z, R0.w;\n" - "ADD R0.x, -R0.y, R0;\n" - "MUL R0.x, R0, R0.z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MAX R1.x, R0.w, c[6].w;\n" - "RCP R1.x, R1.x;\n" - "MAD R1.xyz, -R0, R1.x, c[6].z;\n" - "MAX R2.xyz, R1, c[6].w;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R0, c[6].z;\n" - "MUL R3.xyz, R1, R2.w;\n" - "ADD R2.w, -R1, c[6].z;\n" - "MAD R3.xyz, R0, R2.w, R3;\n" - "MUL R1.xyz, R0.w, R1;\n" - "MAD R0.xyz, R0, R1.w, R1;\n" - "MUL R2.w, R0, R1;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R1, R2, R3;\n" - "MAD R3.xyz, R0.w, R1.w, R3;\n" - "ADD R1.x, R0.w, R1.w;\n" - "ADD R3.xyz, R3, -R2;\n" - "SGE R0.xyz, R0, R2.w;\n" - "MAD result.color.xyz, R0, R3, R2;\n" - "MAD result.color.w, -R0, R1, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORBURN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 2, 4, 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[6];\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RCP R0.z, R0.z;\n" - "ADD R0.x, -R0.y, R0.z;\n" - "RCP R0.y, R0.w;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "ADD R2.w, -R1, c[6].z;\n" - "MAD R2.xyz, -R0.w, R1.w, R3;\n" - "MUL R4.xyz, R0.w, R2;\n" - "MAX R2.xyz, R0, c[6].w;\n" - "MUL R5.xyz, R0, R2.w;\n" - "ADD R3.w, -R0, c[6].z;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R4, R2, R5;\n" - "MUL R4.xyz, R1, R3.w;\n" - "MAD R1.xyz, R1, R3.w, R2;\n" - "MAD R0.xyz, R0, R2.w, R4;\n" - "MUL R2.x, R0.w, R1.w;\n" - "ADD R2.w, R0, R1;\n" - "ADD R1.xyz, R1, -R0;\n" - "SGE R2.xyz, R3, R2.x;\n" - "MAD result.color.xyz, R2, R1, R0;\n" - "MAD result.color.w, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_HARDLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MOV R0.x, c[6];\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.z, R0.y, R0.y, -R0;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RSQ R0.z, R0.z;\n" - "RCP R0.x, R0.z;\n" - "ADD R2.w, -R1, c[6].z;\n" - "RCP R0.z, R0.w;\n" - "ADD R0.x, -R0.y, R0;\n" - "MUL R0.x, R0, R0.z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[6].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MUL R3.xyz, R0, R1;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R2.w, -R0, c[6].z;\n" - "MUL R0.xyz, R0, c[6].x;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "MAD R3.xyz, R3, c[6].x, R4;\n" - "MAD R1.xyz, R1, R2.w, R3;\n" - "ADD R2.w, R0, R1;\n" - "ADD R2.xyz, R2, -R1;\n" - "SGE R0.xyz, R0, R0.w;\n" - "MAD result.color.xyz, R0, R2, R1;\n" - "MAD result.color.w, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SOFTLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..5],\n" - " { 2, 4, 1, 9.9999997e-006 },\n" - " { 16, 12, 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "TEMP R6;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.z, c[6];\n" - "MUL R0.x, R0, c[6];\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MAD R0.y, R0.x, R0.x, -R0;\n" - "RSQ R0.y, R0.y;\n" - "RCP R0.y, R0.y;\n" - "ADD R0.y, -R0.x, R0;\n" - "MOV R0.x, c[6];\n" - "MUL R0.x, R0, c[1];\n" - "MAX R0.z, R1.w, c[6].w;\n" - "RCP R0.z, R0.z;\n" - "MUL R3.xyz, R1, R0.z;\n" - "MAD R4.xyz, R3, c[7].x, -c[7].y;\n" - "RCP R0.x, R0.x;\n" - "MUL R0.x, R0.y, R0;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MAD R2.xyz, R0, c[6].x, -R0.w;\n" - "MAD R4.xyz, R3, R4, c[7].z;\n" - "MUL R5.xyz, R1.w, R2;\n" - "MUL R6.xyz, R5, R4;\n" - "RSQ R2.w, R3.x;\n" - "RCP R4.x, R2.w;\n" - "RSQ R2.w, R3.y;\n" - "RSQ R3.w, R3.z;\n" - "RCP R4.y, R2.w;\n" - "RCP R4.z, R3.w;\n" - "ADD R4.xyz, -R3, R4;\n" - "MUL R6.xyz, R3, R6;\n" - "MUL R4.xyz, R5, R4;\n" - "ADD R3.xyz, -R3, c[6].z;\n" - "MAD R2.xyz, R2, R3, R0.w;\n" - "MUL R3.xyz, R0, c[6].x;\n" - "MAD R5.xyz, R0.w, R1, R6;\n" - "MAD R4.xyz, R0.w, R1, R4;\n" - "ADD R6.xyz, R4, -R5;\n" - "MUL R4.xyz, R1, c[6].y;\n" - "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R6, R5;\n" - "MAD R4.xyz, -R1, R2, R4;\n" - "MUL R2.xyz, R1, R2;\n" - "SGE R3.xyz, R3, R0.w;\n" - "MAD R2.xyz, R3, R4, R2;\n" - "ADD R2.w, -R1, c[6].z;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R0.x, R0.w, R1.w;\n" - "ADD R0.y, -R0.w, c[6].z;\n" - "MAD result.color.xyz, R1, R0.y, R2;\n" - "MAD result.color.w, -R0, R1, R0.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DIFFERENCE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 2, 4 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[6];\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RCP R0.z, R0.z;\n" - "ADD R0.x, -R0.y, R0.z;\n" - "RCP R0.y, R0.w;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "ADD R0.xyz, R0, R1;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R1.x, R0.w, R1.w;\n" - "MAD result.color.xyz, -R2, c[6].x, R0;\n" - "MAD result.color.w, -R0, R1, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_EXCLUSION_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..5],\n" - " { 2, 4, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.x, c[6].x;\n" - "MUL R0.z, R0, c[6].y;\n" - "MAD R0.x, R0.y, R0.y, -R0.z;\n" - "RSQ R0.z, R0.x;\n" - "MOV R0.x, c[6];\n" - "MUL R0.w, R0.x, c[1].x;\n" - "RCP R0.z, R0.z;\n" - "ADD R0.x, -R0.y, R0.z;\n" - "RCP R0.y, R0.w;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "MUL R2.xyz, R0, R1;\n" - "MAD R2.xyz, -R2, c[6].x, R3;\n" - "ADD R2.w, -R1, c[6].z;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[6].z;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODE_BLEND_MODE_MASK = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 2, 4 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "ADD R0.z, R0, R0.w;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.z, c[8];\n" - "MUL R0.x, R0, c[8];\n" - "MAD R0.y, R0.x, R0.x, -R0;\n" - "RSQ R0.y, R0.y;\n" - "RCP R0.y, R0.y;\n" - "ADD R1.x, -R0, R0.y;\n" - "MOV R0.x, c[8];\n" - "MUL R0.x, R0, c[1];\n" - "RCP R1.y, R0.x;\n" - "ADD R0.zw, fragment.position.xyxy, c[6].xyxy;\n" - "MUL R0.zw, R0, c[5].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "MUL R1.x, R1, R1.y;\n" - "DP4 R1.y, R0, c[7];\n" - "TEX R0, R1, texture[1], 1D;\n" - "MUL result.color, R0, R1.y;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODE_BLEND_MODE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 2, 4 } };\n" - "TEMP R0;\n" - "MUL R0.xyz, fragment.position.y, c[3];\n" - "MAD R0.xyz, fragment.position.x, c[2], R0;\n" - "ADD R0.xyz, R0, c[4];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.xyxy;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.z, R0, R0.w;\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, -R0, c[1].x;\n" - "MUL R0.y, R0.z, c[5];\n" - "MUL R0.x, R0, c[5];\n" - "MAD R0.z, R0.x, R0.x, -R0.y;\n" - "MOV R0.y, c[5].x;\n" - "RSQ R0.z, R0.z;\n" - "MUL R0.w, R0.y, c[1].x;\n" - "RCP R0.y, R0.z;\n" - "RCP R0.z, R0.w;\n" - "ADD R0.x, -R0, R0.y;\n" - "MUL R0.x, R0, R0.z;\n" - "TEX result.color, R0, texture[0], 1D;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF = - "!!ARBfp1.0\n" - "PARAM c[13] = { program.local[0..9],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[10].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[11].x, c[11].y;\n" - "MAD R1.z, R1, R1.y, -c[11];\n" - "MAD R1.z, R1, R1.y, c[11].w;\n" - "MAD R1.z, R1, R1.y, -c[12].x;\n" - "MAD R1.y, R1.z, R1, c[12];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[10].w;\n" - "ADD R0.z, -R0, R0.w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[10].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R1.x, R0, c[10];\n" - "FLR R1.y, R1.x;\n" - "MUL R0.xy, fragment.position, c[7];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, R1, -R1.y;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R2.xyz, R0, c[4].y;\n" - "MUL R3.xyz, R1.w, R2;\n" - "MUL R2.xyz, R1, c[4].x;\n" - "MAD R2.xyz, R0.w, R2, R3;\n" - "ADD R3.xy, fragment.position, c[8];\n" - "ADD R2.w, -R0, c[12].z;\n" - "MUL R1.xyz, R1, c[5].y;\n" - "MAD R2.xyz, R2.w, R1, R2;\n" - "MUL R1.xyz, R0, c[5].z;\n" - "ADD R3.z, -R1.w, c[12];\n" - "MAD R2.xyz, R3.z, R1, R2;\n" - "MUL R1.y, R1.w, R2.w;\n" - "MUL R1.x, R1.w, R0.w;\n" - "MUL R1.z, R0.w, R3;\n" - "DP3 R2.w, R1, c[5];\n" - "MUL R3.xy, R3, c[6];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[9];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_MULTIPLY = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..7],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[8].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[9].x, c[9].y;\n" - "MAD R1.z, R1, R1.y, -c[9];\n" - "MAD R1.z, R1, R1.y, c[9].w;\n" - "MAD R1.z, R1, R1.y, -c[10].x;\n" - "MAD R1.y, R1.z, R1, c[10];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[8].w;\n" - "ADD R0.z, -R0, R0.w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[8].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R1.x, R0, c[8];\n" - "FLR R1.y, R1.x;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, R1, -R1.y;\n" - "TEX R1, R1, texture[2], 1D;\n" - "ADD R2.x, -R0.w, c[10].z;\n" - "MUL R2.xyz, R1, R2.x;\n" - "MAD R1.xyz, R1, R0, R2;\n" - "ADD R2.x, -R1.w, c[10].z;\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SCREEN = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..7],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ADD R3.xy, fragment.position, c[6];\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[8].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[9].x, c[9].y;\n" - "MAD R1.z, R1, R1.y, -c[9];\n" - "MAD R1.z, R1, R1.y, c[9].w;\n" - "MAD R1.z, R1, R1.y, -c[10].x;\n" - "MAD R1.y, R1.z, R1, c[10];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[8].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[8].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[8];\n" - "FLR R0.y, R0.x;\n" - "ADD R0.z, R0.x, -R0.y;\n" - "TEX R1, R0.z, texture[2], 1D;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R2, R1, R0;\n" - "MAD R2, -R1, R0, R2;\n" - "MUL R3.xy, R3, c[4];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_OVERLAY = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..7],\n" - " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" - " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" - " { 3.141593, 0.15915494, 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[8];\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[8].y, c[8];\n" - "MAD R1.z, R1, R1.y, -c[8].w;\n" - "MAD R1.z, R1, R1.y, c[9].x;\n" - "MAD R1.z, R1, R1.y, -c[9].y;\n" - "MAD R1.y, R1.z, R1, c[9].z;\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[9].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[10].x;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[10].y;\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R1, c[10];\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[10].z;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MUL R3.xyz, R0, R1;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, -R0.w, c[10].w;\n" - "MAD R3.xyz, R3, c[10].z, R4;\n" - "MAD R3.xyz, R1, R2.x, R3;\n" - "MAD R0.xyz, R1, R2.x, R0;\n" - "MUL R2.xyz, R1, c[10].z;\n" - "ADD R0.xyz, R0, -R3;\n" - "SGE R2.xyz, R2, R1.w;\n" - "MAD R2.xyz, R2, R0, R3;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DARKEN = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..7],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[8].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[9].x, c[9].y;\n" - "MAD R1.z, R1, R1.y, -c[9];\n" - "MAD R1.z, R1, R1.y, c[9].w;\n" - "MAD R1.z, R1, R1.y, -c[10].x;\n" - "MAD R1.y, R1.z, R1, c[10];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[8].w;\n" - "ADD R0.z, -R0, R0.w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[8].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.z, R0.x, c[8].x;\n" - "FLR R0.w, R0.z;\n" - "ADD R1.x, R0.z, -R0.w;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[10].z;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[10].z;\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_LIGHTEN = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..7],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[8].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[9].x, c[9].y;\n" - "MAD R1.z, R1, R1.y, -c[9];\n" - "MAD R1.z, R1, R1.y, c[9].w;\n" - "MAD R1.z, R1, R1.y, -c[10].x;\n" - "MAD R1.y, R1.z, R1, c[10];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[8].w;\n" - "ADD R0.z, -R0, R0.w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[8].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.z, R0.x, c[8].x;\n" - "FLR R0.w, R0.z;\n" - "ADD R1.x, R0.z, -R0.w;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MAX R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[10].z;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[10].z;\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORDODGE = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..7],\n" - " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" - " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" - " { 3.141593, 0.15915494, 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[8];\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[8].y, c[8];\n" - "MAD R1.z, R1, R1.y, -c[8].w;\n" - "MAD R1.z, R1, R1.y, c[9].x;\n" - "MAD R1.z, R1, R1.y, -c[9].y;\n" - "MAD R1.y, R1.z, R1, c[9].z;\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[9].w;\n" - "ADD R0.z, -R0, R0.w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[10].x;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[10].y;\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MAX R1.x, R0.w, c[10].w;\n" - "RCP R1.x, R1.x;\n" - "MAD R1.xyz, -R0, R1.x, c[10].z;\n" - "MAX R2.xyz, R1, c[10].w;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R0, c[10].z;\n" - "MUL R3.xyz, R1, R2.w;\n" - "ADD R2.w, -R1, c[10].z;\n" - "MAD R4.xyz, R0, R2.w, R3;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MUL R2.w, R0, R1;\n" - "MAD R0.xyz, R0, R1.w, R3;\n" - "SGE R0.xyz, R0, R2.w;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R3, R2, R4;\n" - "MAD R4.xyz, R0.w, R1.w, R4;\n" - "ADD R4.xyz, R4, -R2;\n" - "MAD R2.xyz, R0, R4, R2;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORBURN = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..7],\n" - " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" - " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" - " { 3.141593, 0.15915494, 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.w, R0.x;\n" - "ABS R0.z, R0.y;\n" - "ADD R0.z, R0, -R0.w;\n" - "ADD R1.x, R0.y, c[8];\n" - "ABS R0.z, R0;\n" - "CMP R0.y, -R0.z, R0, R1.x;\n" - "ABS R0.z, -R0.y;\n" - "MAX R1.x, R0.w, R0.z;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.w, R0.z;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[8].y, c[8];\n" - "MAD R1.z, R1, R1.y, -c[8].w;\n" - "MAD R1.z, R1, R1.y, c[9].x;\n" - "MAD R1.z, R1, R1.y, -c[9].y;\n" - "MAD R1.y, R1.z, R1, c[9].z;\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[9].w;\n" - "ADD R0.z, -R0.w, R0;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[10].x;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[10].y;\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "MAD R2.xyz, -R0.w, R1.w, R3;\n" - "MUL R4.xyz, R0.w, R2;\n" - "MAX R2.xyz, R0, c[10].w;\n" - "ADD R2.w, -R1, c[10].z;\n" - "ADD R3.w, -R0, c[10].z;\n" - "MUL R5.xyz, R0, R2.w;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R4, R2, R5;\n" - "MUL R4.xyz, R1, R3.w;\n" - "MAD R0.xyz, R0, R2.w, R4;\n" - "MUL R2.w, R0, R1;\n" - "MAD R2.xyz, R1, R3.w, R2;\n" - "ADD R2.xyz, R2, -R0;\n" - "SGE R3.xyz, R3, R2.w;\n" - "MAD R2.xyz, R3, R2, R0;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_HARDLIGHT = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..7],\n" - " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" - " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" - " { 3.141593, 0.15915494, 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[8];\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[8].y, c[8];\n" - "MAD R1.z, R1, R1.y, -c[8].w;\n" - "MAD R1.z, R1, R1.y, c[9].x;\n" - "MAD R1.z, R1, R1.y, -c[9].y;\n" - "MAD R1.y, R1.z, R1, c[9].z;\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[9].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[10].x;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[10].y;\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R1, c[10];\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[10].z;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R3.xyz, R0, R1;\n" - "ADD R2.w, -R0, c[10];\n" - "MAD R3.xyz, R3, c[10].z, R4;\n" - "MUL R0.xyz, R0, c[10].z;\n" - "SGE R0.xyz, R0, R0.w;\n" - "MAD R3.xyz, R1, R2.w, R3;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "ADD R2.xyz, R2, -R3;\n" - "MAD R2.xyz, R0, R2, R3;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SOFTLIGHT = - "!!ARBfp1.0\n" - "PARAM c[13] = { program.local[0..7],\n" - " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" - " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" - " { 3.141593, 0.15915494, 1, 2 },\n" - " { 9.9999997e-006, 4, 16, 12 },\n" - " { 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "TEMP R6;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.w, R0.x;\n" - "ABS R0.z, R0.y;\n" - "ADD R0.z, R0, -R0.w;\n" - "ADD R1.x, R0.y, c[8];\n" - "ABS R0.z, R0;\n" - "CMP R0.y, -R0.z, R0, R1.x;\n" - "ABS R0.z, -R0.y;\n" - "MAX R1.x, R0.w, R0.z;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.w, R0.z;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[8].y, c[8];\n" - "MAD R1.z, R1, R1.y, -c[8].w;\n" - "MAD R1.z, R1, R1.y, c[9].x;\n" - "MAD R1.z, R1, R1.y, -c[9].y;\n" - "MAD R1.y, R1.z, R1, c[9].z;\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[9].w;\n" - "ADD R0.z, -R0.w, R0;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[10].x;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MAX R0.z, R1.w, c[11].x;\n" - "RCP R2.x, R0.z;\n" - "MUL R3.xyz, R1, R2.x;\n" - "MAD R4.xyz, R3, c[11].z, -c[11].w;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[10].y;\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MAD R2.xyz, R0, c[10].w, -R0.w;\n" - "MAD R4.xyz, R3, R4, c[12].x;\n" - "MUL R5.xyz, R1.w, R2;\n" - "MUL R6.xyz, R5, R4;\n" - "RSQ R2.w, R3.x;\n" - "RCP R4.x, R2.w;\n" - "RSQ R2.w, R3.y;\n" - "RSQ R3.w, R3.z;\n" - "RCP R4.y, R2.w;\n" - "RCP R4.z, R3.w;\n" - "ADD R4.xyz, -R3, R4;\n" - "MUL R6.xyz, R3, R6;\n" - "MUL R4.xyz, R5, R4;\n" - "ADD R3.xyz, -R3, c[10].z;\n" - "MAD R2.xyz, R2, R3, R0.w;\n" - "MUL R3.xyz, R0, c[10].w;\n" - "MAD R5.xyz, R0.w, R1, R6;\n" - "MAD R4.xyz, R0.w, R1, R4;\n" - "ADD R6.xyz, R4, -R5;\n" - "MUL R4.xyz, R1, c[11].y;\n" - "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R6, R5;\n" - "MAD R4.xyz, -R1, R2, R4;\n" - "SGE R3.xyz, R3, R0.w;\n" - "MUL R2.xyz, R1, R2;\n" - "ADD R2.w, -R1, c[10].z;\n" - "MAD R2.xyz, R3, R4, R2;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R0.x, -R0.w, c[10].z;\n" - "MAD R2.xyz, R1, R0.x, R2;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DIFFERENCE = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..7],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[8].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[9].x, c[9].y;\n" - "MAD R1.z, R1, R1.y, -c[9];\n" - "MAD R1.z, R1, R1.y, c[9].w;\n" - "MAD R1.z, R1, R1.y, -c[10].x;\n" - "MAD R1.y, R1.z, R1, c[10];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[8].w;\n" - "ADD R0.z, -R0, R0.w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[8].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.z, R0.x, c[8].x;\n" - "FLR R0.w, R0.z;\n" - "ADD R1.x, R0.z, -R0.w;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "ADD R2.xyz, R1, R0;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R1.xyz, R1, R0.w;\n" - "MIN R1.xyz, R1, R3;\n" - "MAD R2.xyz, -R1, c[10].z, R2;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_EXCLUSION = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..7],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[8].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[9].x, c[9].y;\n" - "MAD R1.z, R1, R1.y, -c[9];\n" - "MAD R1.z, R1, R1.y, c[9].w;\n" - "MAD R1.z, R1, R1.y, -c[10].x;\n" - "MAD R1.y, R1.z, R1, c[10];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[8].w;\n" - "ADD R0.z, -R0, R0.w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[8].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.z, R0.x, c[8].x;\n" - "FLR R0.w, R0.z;\n" - "ADD R1.x, R0.z, -R0.w;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R2.xyz, R1.w, R0;\n" - "MAD R3.xyz, R1, R0.w, R2;\n" - "MUL R2.xyz, R1, R0;\n" - "MAD R2.xyz, -R2, c[10].z, R3;\n" - "ADD R2.w, -R0, c[10];\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[10].w;\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..6],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[7].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[8].x, c[8].y;\n" - "MAD R1.z, R1, R1.y, -c[8];\n" - "MAD R1.z, R1, R1.y, c[8].w;\n" - "MAD R1.z, R1, R1.y, -c[9].x;\n" - "MAD R1.y, R1.z, R1, c[9];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[7].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[7].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R2.xyz, R1, c[4].y;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[7];\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R3.xyz, R0.w, R2;\n" - "MUL R2.xyz, R0, c[4].x;\n" - "MAD R2.xyz, R1.w, R2, R3;\n" - "ADD R2.w, -R1, c[9].z;\n" - "MUL R0.xyz, R0, c[5].y;\n" - "MAD R0.xyz, R2.w, R0, R2;\n" - "ADD R2.x, -R0.w, c[9].z;\n" - "MUL R1.xyz, R1, c[5].z;\n" - "MAD result.color.xyz, R2.x, R1, R0;\n" - "MUL R0.x, R0.w, R1.w;\n" - "MUL R0.z, R1.w, R2.x;\n" - "MUL R0.y, R0.w, R2.w;\n" - "DP3 result.color.w, R0, c[5];\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_MULTIPLY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..4],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[5].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[6].x, c[6].y;\n" - "MAD R1.z, R1, R1.y, -c[6];\n" - "MAD R1.z, R1, R1.y, c[6].w;\n" - "MAD R1.z, R1, R1.y, -c[7].x;\n" - "MAD R1.y, R1.z, R1, c[7];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[5].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[5].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[5];\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "ADD R2.x, -R1.w, c[7].z;\n" - "MUL R2.xyz, R0, R2.x;\n" - "MAD R0.xyz, R0, R1, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[7].z;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SCREEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..4],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[5].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[6].x, c[6].y;\n" - "MAD R1.z, R1, R1.y, -c[6];\n" - "MAD R1.z, R1, R1.y, c[6].w;\n" - "MAD R1.z, R1, R1.y, -c[7].x;\n" - "MAD R1.y, R1.z, R1, c[7];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[5].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[5].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[5];\n" - "FLR R0.y, R0.x;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "ADD R2, R0, R1;\n" - "MAD result.color, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_OVERLAY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..4],\n" - " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" - " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" - " { 3.141593, 0.15915494, 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[5];\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[5].y, c[5];\n" - "MAD R1.z, R1, R1.y, -c[5].w;\n" - "MAD R1.z, R1, R1.y, c[6].x;\n" - "MAD R1.z, R1, R1.y, -c[6].y;\n" - "MAD R1.y, R1.z, R1, c[6].z;\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[6].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[7].x;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[7].y;\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[7];\n" - "MUL R2.xyz, R2, c[7].z;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R3.xyz, R0, R2.w;\n" - "MUL R0.xyz, R0, R1;\n" - "ADD R2.w, -R0, c[7];\n" - "MAD R0.xyz, R0, c[7].z, R3;\n" - "MAD R0.xyz, R1, R2.w, R0;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "MUL R1.xyz, R1, c[7].z;\n" - "ADD R2.w, R0, R1;\n" - "ADD R2.xyz, R2, -R0;\n" - "SGE R1.xyz, R1, R1.w;\n" - "MAD result.color.xyz, R1, R2, R0;\n" - "MAD result.color.w, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DARKEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..4],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[5].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[6].x, c[6].y;\n" - "MAD R1.z, R1, R1.y, -c[6];\n" - "MAD R1.z, R1, R1.y, c[6].w;\n" - "MAD R1.z, R1, R1.y, -c[7].x;\n" - "MAD R1.y, R1.z, R1, c[7];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[5].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[5].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[5];\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[7].z;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[7].z;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_LIGHTEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..4],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[5].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[6].x, c[6].y;\n" - "MAD R1.z, R1, R1.y, -c[6];\n" - "MAD R1.z, R1, R1.y, c[6].w;\n" - "MAD R1.z, R1, R1.y, -c[7].x;\n" - "MAD R1.y, R1.z, R1, c[7];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[5].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[5].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[5];\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MAX R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[7].z;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[7].z;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORDODGE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..4],\n" - " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" - " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" - " { 3.141593, 0.15915494, 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[5];\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[5].y, c[5];\n" - "MAD R1.z, R1, R1.y, -c[5].w;\n" - "MAD R1.z, R1, R1.y, c[6].x;\n" - "MAD R1.z, R1, R1.y, -c[6].y;\n" - "MAD R1.y, R1.z, R1, c[6].z;\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[6].w;\n" - "ADD R0.z, -R0, R0.w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[7].x;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[7].y;\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MAX R1.x, R0.w, c[7].w;\n" - "RCP R1.x, R1.x;\n" - "MAD R1.xyz, -R0, R1.x, c[7].z;\n" - "MAX R2.xyz, R1, c[7].w;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R0, c[7].z;\n" - "MUL R3.xyz, R1, R2.w;\n" - "ADD R2.w, -R1, c[7].z;\n" - "MAD R3.xyz, R0, R2.w, R3;\n" - "MUL R1.xyz, R0.w, R1;\n" - "MAD R0.xyz, R0, R1.w, R1;\n" - "MUL R2.w, R0, R1;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R1, R2, R3;\n" - "MAD R3.xyz, R0.w, R1.w, R3;\n" - "ADD R1.x, R0.w, R1.w;\n" - "ADD R3.xyz, R3, -R2;\n" - "SGE R0.xyz, R0, R2.w;\n" - "MAD result.color.xyz, R0, R3, R2;\n" - "MAD result.color.w, -R0, R1, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORBURN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..4],\n" - " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" - " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" - " { 3.141593, 0.15915494, 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.w, R0.x;\n" - "ABS R0.z, R0.y;\n" - "ADD R0.z, R0, -R0.w;\n" - "ADD R1.x, R0.y, c[5];\n" - "ABS R0.z, R0;\n" - "CMP R0.y, -R0.z, R0, R1.x;\n" - "ABS R0.z, -R0.y;\n" - "MAX R1.x, R0.w, R0.z;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.w, R0.z;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[5].y, c[5];\n" - "MAD R1.z, R1, R1.y, -c[5].w;\n" - "MAD R1.z, R1, R1.y, c[6].x;\n" - "MAD R1.z, R1, R1.y, -c[6].y;\n" - "MAD R1.y, R1.z, R1, c[6].z;\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[6].w;\n" - "ADD R0.z, -R0.w, R0;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[7].x;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[7].y;\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "ADD R2.w, -R1, c[7].z;\n" - "MAD R2.xyz, -R0.w, R1.w, R3;\n" - "MUL R4.xyz, R0.w, R2;\n" - "MAX R2.xyz, R0, c[7].w;\n" - "MUL R5.xyz, R0, R2.w;\n" - "ADD R3.w, -R0, c[7].z;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R4, R2, R5;\n" - "MUL R4.xyz, R1, R3.w;\n" - "MAD R1.xyz, R1, R3.w, R2;\n" - "MAD R0.xyz, R0, R2.w, R4;\n" - "MUL R2.x, R0.w, R1.w;\n" - "ADD R2.w, R0, R1;\n" - "ADD R1.xyz, R1, -R0;\n" - "SGE R2.xyz, R3, R2.x;\n" - "MAD result.color.xyz, R2, R1, R0;\n" - "MAD result.color.w, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_HARDLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..4],\n" - " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" - " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" - " { 3.141593, 0.15915494, 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[5];\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[5].y, c[5];\n" - "MAD R1.z, R1, R1.y, -c[5].w;\n" - "MAD R1.z, R1, R1.y, c[6].x;\n" - "MAD R1.z, R1, R1.y, -c[6].y;\n" - "MAD R1.y, R1.z, R1, c[6].z;\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[6].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[7].x;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[7].y;\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R1, c[7];\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[7].z;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MUL R3.xyz, R0, R1;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R2.w, -R0, c[7];\n" - "MUL R0.xyz, R0, c[7].z;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "MAD R3.xyz, R3, c[7].z, R4;\n" - "MAD R1.xyz, R1, R2.w, R3;\n" - "ADD R2.w, R0, R1;\n" - "ADD R2.xyz, R2, -R1;\n" - "SGE R0.xyz, R0, R0.w;\n" - "MAD result.color.xyz, R0, R2, R1;\n" - "MAD result.color.w, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SOFTLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..4],\n" - " { 0.0020000001, -0.01348047, 0.05747731, 0.1212391 },\n" - " { 0.1956359, 0.33299461, 0.99999559, 1.570796 },\n" - " { 3.141593, 0.15915494, 1, 2 },\n" - " { 9.9999997e-006, 4, 16, 12 },\n" - " { 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "TEMP R6;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.w, R0.x;\n" - "ABS R0.z, R0.y;\n" - "ADD R0.z, R0, -R0.w;\n" - "ADD R1.x, R0.y, c[5];\n" - "ABS R0.z, R0;\n" - "CMP R0.y, -R0.z, R0, R1.x;\n" - "ABS R0.z, -R0.y;\n" - "MAX R1.x, R0.w, R0.z;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.w, R0.z;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[5].y, c[5];\n" - "MAD R1.z, R1, R1.y, -c[5].w;\n" - "MAD R1.z, R1, R1.y, c[6].x;\n" - "MAD R1.z, R1, R1.y, -c[6].y;\n" - "MAD R1.y, R1.z, R1, c[6].z;\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[6].w;\n" - "ADD R0.z, -R0.w, R0;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[7].x;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MAX R0.z, R1.w, c[8].x;\n" - "RCP R2.x, R0.z;\n" - "MUL R3.xyz, R1, R2.x;\n" - "MAD R4.xyz, R3, c[8].z, -c[8].w;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[7].y;\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MAD R2.xyz, R0, c[7].w, -R0.w;\n" - "MAD R4.xyz, R3, R4, c[9].x;\n" - "MUL R5.xyz, R1.w, R2;\n" - "MUL R6.xyz, R5, R4;\n" - "RSQ R2.w, R3.x;\n" - "RCP R4.x, R2.w;\n" - "RSQ R2.w, R3.y;\n" - "RSQ R3.w, R3.z;\n" - "RCP R4.y, R2.w;\n" - "RCP R4.z, R3.w;\n" - "ADD R4.xyz, -R3, R4;\n" - "MUL R6.xyz, R3, R6;\n" - "MUL R4.xyz, R5, R4;\n" - "ADD R3.xyz, -R3, c[7].z;\n" - "MAD R2.xyz, R2, R3, R0.w;\n" - "MUL R3.xyz, R0, c[7].w;\n" - "MAD R5.xyz, R0.w, R1, R6;\n" - "MAD R4.xyz, R0.w, R1, R4;\n" - "ADD R6.xyz, R4, -R5;\n" - "MUL R4.xyz, R1, c[8].y;\n" - "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R6, R5;\n" - "MAD R4.xyz, -R1, R2, R4;\n" - "MUL R2.xyz, R1, R2;\n" - "SGE R3.xyz, R3, R0.w;\n" - "MAD R2.xyz, R3, R4, R2;\n" - "ADD R2.w, -R1, c[7].z;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R0.x, R0.w, R1.w;\n" - "ADD R0.y, -R0.w, c[7].z;\n" - "MAD result.color.xyz, R1, R0.y, R2;\n" - "MAD result.color.w, -R0, R1, R0.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DIFFERENCE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..4],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[5].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[6].x, c[6].y;\n" - "MAD R1.z, R1, R1.y, -c[6];\n" - "MAD R1.z, R1, R1.y, c[6].w;\n" - "MAD R1.z, R1, R1.y, -c[7].x;\n" - "MAD R1.y, R1.z, R1, c[7];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[5].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[5].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[5];\n" - "FLR R0.y, R0.x;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "ADD R0.xyz, R0, R1;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R1.x, R0.w, R1.w;\n" - "MAD result.color.xyz, -R2, c[7].z, R0;\n" - "MAD result.color.w, -R0, R1, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_EXCLUSION_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..4],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559, 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[5].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[6].x, c[6].y;\n" - "MAD R1.z, R1, R1.y, -c[6];\n" - "MAD R1.z, R1, R1.y, c[6].w;\n" - "MAD R1.z, R1, R1.y, -c[7].x;\n" - "MAD R1.y, R1.z, R1, c[7];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[5].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[5].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[5];\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "MUL R2.xyz, R0, R1;\n" - "MAD R2.xyz, -R2, c[7].z, R3;\n" - "ADD R2.w, -R1, c[7];\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[7].w;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODE_BLEND_MODE_MASK = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..6],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[7].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[8].x, c[8].y;\n" - "MAD R1.z, R1, R1.y, -c[8];\n" - "MAD R1.z, R1, R1.y, c[8].w;\n" - "MAD R1.z, R1, R1.y, -c[9].x;\n" - "MAD R1.y, R1.z, R1, c[9];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R1.y, -R1.x, c[7].w;\n" - "ADD R0.z, -R0, R0.w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[7].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R1.x, R0, c[7];\n" - "FLR R1.y, R1.x;\n" - "ADD R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "MUL R0.xy, R0.zwzw, c[4];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, R1, -R1.y;\n" - "DP4 R1.y, R0, c[6];\n" - "TEX R0, R1, texture[1], 1D;\n" - "MUL result.color, R0, R1.y;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODE_BLEND_MODE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..3],\n" - " { 0.15915494, 0.0020000001, 3.141593, 1.570796 },\n" - " { -0.01348047, 0.05747731, 0.1212391, 0.1956359 },\n" - " { 0.33299461, 0.99999559 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "ABS R0.z, R0.x;\n" - "ABS R0.w, R0.y;\n" - "ADD R0.w, R0, -R0.z;\n" - "ADD R1.x, R0.y, c[4].y;\n" - "ABS R0.w, R0;\n" - "CMP R0.y, -R0.w, R0, R1.x;\n" - "ABS R0.w, -R0.y;\n" - "MAX R1.x, R0.z, R0.w;\n" - "RCP R1.y, R1.x;\n" - "MIN R1.x, R0.z, R0.w;\n" - "MUL R1.x, R1, R1.y;\n" - "MUL R1.y, R1.x, R1.x;\n" - "MAD R1.z, R1.y, c[5].x, c[5].y;\n" - "MAD R1.z, R1, R1.y, -c[5];\n" - "MAD R1.z, R1, R1.y, c[5].w;\n" - "MAD R1.z, R1, R1.y, -c[6].x;\n" - "MAD R1.y, R1.z, R1, c[6];\n" - "MUL R1.x, R1.y, R1;\n" - "ADD R0.z, -R0, R0.w;\n" - "ADD R1.y, -R1.x, c[4].w;\n" - "CMP R0.z, -R0, R1.y, R1.x;\n" - "ADD R0.w, -R0.z, c[4].z;\n" - "CMP R0.x, R0, R0.w, R0.z;\n" - "CMP R0.x, -R0.y, -R0, R0;\n" - "ADD R0.x, R0, c[0];\n" - "MUL R0.x, R0, c[4];\n" - "FLR R0.y, R0.x;\n" - "ADD R0.x, R0, -R0.y;\n" - "TEX result.color, R0, texture[0], 1D;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SIMPLE_PORTER_DUFF = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..9],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, c[0].xyxy;\n" - "ADD R1.x, R0.z, R0.w;\n" - "MUL R0.xy, fragment.position, c[7];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.x, R1, c[0].z;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R2.xyz, R0, c[4].y;\n" - "MUL R3.xyz, R1.w, R2;\n" - "MUL R2.xyz, R1, c[4].x;\n" - "MAD R2.xyz, R0.w, R2, R3;\n" - "ADD R3.xy, fragment.position, c[8];\n" - "ADD R2.w, -R0, c[10].x;\n" - "MUL R1.xyz, R1, c[5].y;\n" - "MAD R2.xyz, R2.w, R1, R2;\n" - "MUL R1.xyz, R0, c[5].z;\n" - "ADD R3.z, -R1.w, c[10].x;\n" - "MAD R2.xyz, R3.z, R1, R2;\n" - "MUL R1.y, R1.w, R2.w;\n" - "MUL R1.x, R1.w, R0.w;\n" - "MUL R1.z, R0.w, R3;\n" - "DP3 R2.w, R1, c[5];\n" - "MUL R3.xy, R3, c[6];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[9];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_MULTIPLY = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, c[0].xyxy;\n" - "ADD R1.x, R0.z, R0.w;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.x, R1, c[0].z;\n" - "TEX R1, R1, texture[2], 1D;\n" - "ADD R2.x, -R0.w, c[8];\n" - "MUL R2.xyz, R1, R2.x;\n" - "MAD R1.xyz, R1, R0, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SCREEN = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..7] };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.z, R0.x, c[0];\n" - "ADD R3.xy, fragment.position, c[6];\n" - "TEX R1, R0.z, texture[2], 1D;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R2, R1, R0;\n" - "MAD R2, -R1, R0, R2;\n" - "MUL R3.xy, R3, c[4];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_OVERLAY = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R1, c[8].y;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[8].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MUL R3.xyz, R0, R1;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, -R0.w, c[8].y;\n" - "MAD R3.xyz, R3, c[8].x, R4;\n" - "MAD R3.xyz, R1, R2.x, R3;\n" - "MAD R0.xyz, R1, R2.x, R0;\n" - "MUL R2.xyz, R1, c[8].x;\n" - "ADD R0.xyz, R0, -R3;\n" - "SGE R2.xyz, R2, R1.w;\n" - "MAD R2.xyz, R2, R0, R3;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_DARKEN = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.z, R0.x, R0.y;\n" - "MUL R1.x, R0.z, c[0].z;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_LIGHTEN = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.z, R0.x, R0.y;\n" - "MUL R1.x, R0.z, c[0].z;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MAX R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORDODGE = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MAX R1.x, R0.w, c[8].y;\n" - "RCP R1.x, R1.x;\n" - "MAD R2.xyz, -R0, R1.x, c[8].x;\n" - "MAX R2.xyz, R2, c[8].y;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MUL R3.xyz, R1, R2.w;\n" - "ADD R2.w, -R1, c[8].x;\n" - "MAD R4.xyz, R0, R2.w, R3;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MUL R2.w, R0, R1;\n" - "MAD R0.xyz, R0, R1.w, R3;\n" - "SGE R0.xyz, R0, R2.w;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R3, R2, R4;\n" - "MAD R4.xyz, R0.w, R1.w, R4;\n" - "ADD R4.xyz, R4, -R2;\n" - "MAD R2.xyz, R0, R4, R2;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORBURN = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "MAD R2.xyz, -R0.w, R1.w, R3;\n" - "MUL R4.xyz, R0.w, R2;\n" - "MAX R2.xyz, R0, c[8].y;\n" - "ADD R2.w, -R1, c[8].x;\n" - "MUL R5.xyz, R0, R2.w;\n" - "ADD R3.w, -R0, c[8].x;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R4, R2, R5;\n" - "MUL R4.xyz, R1, R3.w;\n" - "MAD R0.xyz, R0, R2.w, R4;\n" - "MUL R2.w, R0, R1;\n" - "MAD R2.xyz, R1, R3.w, R2;\n" - "ADD R2.xyz, R2, -R0;\n" - "SGE R3.xyz, R3, R2.w;\n" - "MAD R2.xyz, R3, R2, R0;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_HARDLIGHT = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R1, c[8].y;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[8].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R3.xyz, R0, R1;\n" - "ADD R2.w, -R0, c[8].y;\n" - "MAD R3.xyz, R3, c[8].x, R4;\n" - "MUL R0.xyz, R0, c[8].x;\n" - "SGE R0.xyz, R0, R0.w;\n" - "MAD R3.xyz, R1, R2.w, R3;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "ADD R2.xyz, R2, -R3;\n" - "MAD R2.xyz, R0, R2, R3;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SOFTLIGHT = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..7],\n" - " { 1, 2, 9.9999997e-006, 4 },\n" - " { 16, 12, 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "TEMP R6;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MAX R0.z, R1.w, c[8];\n" - "RCP R0.z, R0.z;\n" - "MUL R3.xyz, R1, R0.z;\n" - "MAD R2.xyz, R3, c[9].x, -c[9].y;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[2], 1D;\n" - "MAD R4.xyz, R3, R2, c[9].z;\n" - "MAD R2.xyz, R0, c[8].y, -R0.w;\n" - "MUL R5.xyz, R1.w, R2;\n" - "MUL R6.xyz, R5, R4;\n" - "RSQ R2.w, R3.x;\n" - "RCP R4.x, R2.w;\n" - "RSQ R2.w, R3.y;\n" - "RSQ R3.w, R3.z;\n" - "RCP R4.y, R2.w;\n" - "RCP R4.z, R3.w;\n" - "ADD R4.xyz, -R3, R4;\n" - "MUL R6.xyz, R3, R6;\n" - "MUL R4.xyz, R5, R4;\n" - "ADD R3.xyz, -R3, c[8].x;\n" - "MAD R2.xyz, R2, R3, R0.w;\n" - "MUL R3.xyz, R0, c[8].y;\n" - "MAD R5.xyz, R0.w, R1, R6;\n" - "MAD R4.xyz, R0.w, R1, R4;\n" - "ADD R6.xyz, R4, -R5;\n" - "MUL R4.xyz, R1, c[8].w;\n" - "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R6, R5;\n" - "MAD R4.xyz, -R1, R2, R4;\n" - "SGE R3.xyz, R3, R0.w;\n" - "MUL R2.xyz, R1, R2;\n" - "ADD R2.w, -R1, c[8].x;\n" - "MAD R2.xyz, R3, R4, R2;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R0.x, -R0.w, c[8];\n" - "MAD R2.xyz, R1, R0.x, R2;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_DIFFERENCE = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.z, R0.x, R0.y;\n" - "MUL R1.x, R0.z, c[0].z;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "ADD R2.xyz, R1, R0;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R1.xyz, R1, R0.w;\n" - "MIN R1.xyz, R1, R3;\n" - "MAD R2.xyz, -R1, c[8].x, R2;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_EXCLUSION = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.z, R0.x, R0.y;\n" - "MUL R1.x, R0.z, c[0].z;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 1D;\n" - "MUL R2.xyz, R1.w, R0;\n" - "MAD R3.xyz, R1, R0.w, R2;\n" - "MUL R2.xyz, R1, R0;\n" - "MAD R2.xyz, -R2, c[8].x, R3;\n" - "ADD R2.w, -R0, c[8].y;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[8].y;\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..6],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R2.xyz, R1, c[4].y;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R3.xyz, R0.w, R2;\n" - "MUL R2.xyz, R0, c[4].x;\n" - "MAD R2.xyz, R1.w, R2, R3;\n" - "ADD R2.w, -R1, c[7].x;\n" - "MUL R0.xyz, R0, c[5].y;\n" - "MAD R0.xyz, R2.w, R0, R2;\n" - "ADD R2.x, -R0.w, c[7];\n" - "MUL R1.xyz, R1, c[5].z;\n" - "MAD result.color.xyz, R2.x, R1, R0;\n" - "MUL R0.x, R0.w, R1.w;\n" - "MUL R0.z, R1.w, R2.x;\n" - "MUL R0.y, R0.w, R2.w;\n" - "DP3 result.color.w, R0, c[5];\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_MULTIPLY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "ADD R2.x, -R1.w, c[5];\n" - "MUL R2.xyz, R0, R2.x;\n" - "MAD R0.xyz, R0, R1, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[5].x;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SCREEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..4] };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "ADD R2, R0, R1;\n" - "MAD result.color, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_OVERLAY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[5].y;\n" - "MUL R2.xyz, R2, c[5].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R3.xyz, R0, R2.w;\n" - "MUL R0.xyz, R0, R1;\n" - "ADD R2.w, -R0, c[5].y;\n" - "MAD R0.xyz, R0, c[5].x, R3;\n" - "MAD R0.xyz, R1, R2.w, R0;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "MUL R1.xyz, R1, c[5].x;\n" - "ADD R2.w, R0, R1;\n" - "ADD R2.xyz, R2, -R0;\n" - "SGE R1.xyz, R1, R1.w;\n" - "MAD result.color.xyz, R1, R2, R0;\n" - "MAD result.color.w, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_DARKEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[5].x;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_LIGHTEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MAX R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[5].x;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORDODGE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MAX R1.x, R0.w, c[5].y;\n" - "RCP R1.x, R1.x;\n" - "MAD R3.xyz, -R0, R1.x, c[5].x;\n" - "MAX R3.xyz, R3, c[5].y;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.x, -R0.w, c[5];\n" - "MUL R2.xyz, R1, R2.x;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R1.xyz, R0.w, R1;\n" - "MAD R0.xyz, R0, R1.w, R1;\n" - "MUL R2.w, R0, R1;\n" - "RCP R3.x, R3.x;\n" - "RCP R3.y, R3.y;\n" - "RCP R3.z, R3.z;\n" - "MAD R3.xyz, R1, R3, R2;\n" - "MAD R2.xyz, R0.w, R1.w, R2;\n" - "ADD R1.x, R0.w, R1.w;\n" - "ADD R2.xyz, R2, -R3;\n" - "SGE R0.xyz, R0, R2.w;\n" - "MAD result.color.xyz, R0, R2, R3;\n" - "MAD result.color.w, -R0, R1, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORBURN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R2.xyz, -R0.w, R1.w, R3;\n" - "MUL R4.xyz, R0.w, R2;\n" - "MAX R2.xyz, R0, c[5].y;\n" - "MUL R5.xyz, R0, R2.w;\n" - "ADD R3.w, -R0, c[5].x;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R4, R2, R5;\n" - "MUL R4.xyz, R1, R3.w;\n" - "MAD R1.xyz, R1, R3.w, R2;\n" - "MAD R0.xyz, R0, R2.w, R4;\n" - "MUL R2.x, R0.w, R1.w;\n" - "ADD R2.w, R0, R1;\n" - "ADD R1.xyz, R1, -R0;\n" - "SGE R2.xyz, R3, R2.x;\n" - "MAD result.color.xyz, R2, R1, R0;\n" - "MAD result.color.w, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_HARDLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R1, c[5].y;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[5].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MUL R3.xyz, R0, R1;\n" - "MUL R0.xyz, R0, c[5].x;\n" - "ADD R2.w, -R0, c[5].y;\n" - "MAD R3.xyz, R3, c[5].x, R4;\n" - "MAD R3.xyz, R1, R2.w, R3;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R1.xyz, R1, -R3;\n" - "SGE R0.xyz, R0, R0.w;\n" - "MAD result.color.xyz, R0, R1, R3;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SOFTLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..4],\n" - " { 1, 2, 9.9999997e-006, 4 },\n" - " { 16, 12, 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "TEMP R6;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MAX R0.z, R1.w, c[5];\n" - "RCP R0.z, R0.z;\n" - "MUL R3.xyz, R1, R0.z;\n" - "MAD R2.xyz, R3, c[6].x, -c[6].y;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MAD R4.xyz, R3, R2, c[6].z;\n" - "MAD R2.xyz, R0, c[5].y, -R0.w;\n" - "MUL R5.xyz, R1.w, R2;\n" - "MUL R6.xyz, R5, R4;\n" - "RSQ R2.w, R3.x;\n" - "RCP R4.x, R2.w;\n" - "RSQ R2.w, R3.y;\n" - "RSQ R3.w, R3.z;\n" - "RCP R4.y, R2.w;\n" - "RCP R4.z, R3.w;\n" - "ADD R4.xyz, -R3, R4;\n" - "MUL R6.xyz, R3, R6;\n" - "MUL R4.xyz, R5, R4;\n" - "ADD R3.xyz, -R3, c[5].x;\n" - "MAD R2.xyz, R2, R3, R0.w;\n" - "MUL R3.xyz, R0, c[5].y;\n" - "MAD R5.xyz, R0.w, R1, R6;\n" - "MAD R4.xyz, R0.w, R1, R4;\n" - "ADD R6.xyz, R4, -R5;\n" - "MUL R4.xyz, R1, c[5].w;\n" - "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R6, R5;\n" - "MAD R4.xyz, -R1, R2, R4;\n" - "MUL R2.xyz, R1, R2;\n" - "SGE R3.xyz, R3, R0.w;\n" - "MAD R2.xyz, R3, R4, R2;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R0.x, R0.w, R1.w;\n" - "ADD R0.y, -R0.w, c[5].x;\n" - "MAD result.color.xyz, R1, R0.y, R2;\n" - "MAD result.color.w, -R0, R1, R0.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_DIFFERENCE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "ADD R0.xyz, R0, R1;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R1.x, R0.w, R1.w;\n" - "MAD result.color.xyz, -R2, c[5].x, R0;\n" - "MAD result.color.w, -R0, R1, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_EXCLUSION_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX R0, R0, texture[1], 1D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "MUL R2.xyz, R0, R1;\n" - "MAD R2.xyz, -R2, c[5].x, R3;\n" - "ADD R2.w, -R1, c[5].y;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[5];\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODE_BLEND_MODE_MASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..6] };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.z;\n" - "MUL R0.zw, R0, c[0].xyxy;\n" - "ADD R1.x, R0.z, R0.w;\n" - "ADD R0.xy, fragment.position, c[5];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[0], 2D;\n" - "DP4 R1.y, R0, c[6];\n" - "MUL R1.x, R1, c[0].z;\n" - "TEX R0, R1, texture[1], 1D;\n" - "MUL result.color, R0, R1.y;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODE_BLEND_MODE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[4] = { program.local[0..3] };\n" - "TEMP R0;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "ADD R0.x, R0, R0.y;\n" - "MUL R0.x, R0, c[0].z;\n" - "TEX result.color, R0, texture[0], 1D;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SIMPLE_PORTER_DUFF = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..9],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R1.xyz, R0, c[3];\n" - "RCP R0.z, R1.z;\n" - "MUL R1.xy, R1, R0.z;\n" - "MUL R0.xy, fragment.position, c[7];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1, R1, texture[2], 2D;\n" - "MUL R2.xyz, R0, c[4].y;\n" - "MUL R3.xyz, R1.w, R2;\n" - "MUL R2.xyz, R1, c[4].x;\n" - "MAD R2.xyz, R0.w, R2, R3;\n" - "ADD R3.xy, fragment.position, c[8];\n" - "ADD R2.w, -R0, c[10].x;\n" - "MUL R1.xyz, R1, c[5].y;\n" - "MAD R2.xyz, R2.w, R1, R2;\n" - "MUL R1.xyz, R0, c[5].z;\n" - "ADD R3.z, -R1.w, c[10].x;\n" - "MAD R2.xyz, R3.z, R1, R2;\n" - "MUL R1.y, R1.w, R2.w;\n" - "MUL R1.x, R1.w, R0.w;\n" - "MUL R1.z, R0.w, R3;\n" - "DP3 R2.w, R1, c[5];\n" - "MUL R3.xy, R3, c[6];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[9];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_MULTIPLY = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R1.xyz, R0, c[3];\n" - "RCP R0.z, R1.z;\n" - "MUL R1.xy, R1, R0.z;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1, R1, texture[2], 2D;\n" - "ADD R2.x, -R0.w, c[8];\n" - "MUL R2.xyz, R1, R2.x;\n" - "MAD R1.xyz, R1, R0, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SCREEN = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..7] };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, c[0].xyxy;\n" - "ADD R3.xy, fragment.position, c[6];\n" - "TEX R1, R0.zwzw, texture[2], 2D;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R2, R1, R0;\n" - "MAD R2, -R1, R0, R2;\n" - "MUL R3.xy, R3, c[4];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_OVERLAY = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[2], 2D;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R1, c[8].y;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[8].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MUL R3.xyz, R0, R1;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, -R0.w, c[8].y;\n" - "MAD R3.xyz, R3, c[8].x, R4;\n" - "MAD R3.xyz, R1, R2.x, R3;\n" - "MAD R0.xyz, R1, R2.x, R0;\n" - "MUL R2.xyz, R1, c[8].x;\n" - "ADD R0.xyz, R0, -R3;\n" - "SGE R2.xyz, R2, R1.w;\n" - "MAD R2.xyz, R2, R0, R3;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_DARKEN = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.z;\n" - "MUL R1.xy, R0.zwzw, c[0];\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 2D;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_LIGHTEN = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.z;\n" - "MUL R1.xy, R0.zwzw, c[0];\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 2D;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MAX R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORDODGE = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[2], 2D;\n" - "MAX R1.x, R0.w, c[8].y;\n" - "RCP R1.x, R1.x;\n" - "MAD R2.xyz, -R0, R1.x, c[8].x;\n" - "MAX R2.xyz, R2, c[8].y;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MUL R3.xyz, R1, R2.w;\n" - "ADD R2.w, -R1, c[8].x;\n" - "MAD R4.xyz, R0, R2.w, R3;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MUL R2.w, R0, R1;\n" - "MAD R0.xyz, R0, R1.w, R3;\n" - "SGE R0.xyz, R0, R2.w;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R3, R2, R4;\n" - "MAD R4.xyz, R0.w, R1.w, R4;\n" - "ADD R4.xyz, R4, -R2;\n" - "MAD R2.xyz, R0, R4, R2;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORBURN = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[2], 2D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "MAD R2.xyz, -R0.w, R1.w, R3;\n" - "MUL R4.xyz, R0.w, R2;\n" - "MAX R2.xyz, R0, c[8].y;\n" - "ADD R2.w, -R1, c[8].x;\n" - "MUL R5.xyz, R0, R2.w;\n" - "ADD R3.w, -R0, c[8].x;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R4, R2, R5;\n" - "MUL R4.xyz, R1, R3.w;\n" - "MAD R0.xyz, R0, R2.w, R4;\n" - "MUL R2.w, R0, R1;\n" - "MAD R2.xyz, R1, R3.w, R2;\n" - "ADD R2.xyz, R2, -R0;\n" - "SGE R3.xyz, R3, R2.w;\n" - "MAD R2.xyz, R3, R2, R0;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_HARDLIGHT = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[2], 2D;\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R1, c[8].y;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[8].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R3.xyz, R0, R1;\n" - "ADD R2.w, -R0, c[8].y;\n" - "MAD R3.xyz, R3, c[8].x, R4;\n" - "MUL R0.xyz, R0, c[8].x;\n" - "SGE R0.xyz, R0, R0.w;\n" - "MAD R3.xyz, R1, R2.w, R3;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "ADD R2.xyz, R2, -R3;\n" - "MAD R2.xyz, R0, R2, R3;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SOFTLIGHT = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..7],\n" - " { 1, 2, 9.9999997e-006, 4 },\n" - " { 16, 12, 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "TEMP R6;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MUL R1.xy, fragment.position, c[5];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MAX R0.w, R1, c[8].z;\n" - "RCP R0.w, R0.w;\n" - "MUL R3.xyz, R1, R0.w;\n" - "MAD R2.xyz, R3, c[9].x, -c[9].y;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[2], 2D;\n" - "MAD R4.xyz, R3, R2, c[9].z;\n" - "MAD R2.xyz, R0, c[8].y, -R0.w;\n" - "MUL R5.xyz, R1.w, R2;\n" - "MUL R6.xyz, R5, R4;\n" - "RSQ R2.w, R3.x;\n" - "RCP R4.x, R2.w;\n" - "RSQ R2.w, R3.y;\n" - "RSQ R3.w, R3.z;\n" - "RCP R4.y, R2.w;\n" - "RCP R4.z, R3.w;\n" - "ADD R4.xyz, -R3, R4;\n" - "MUL R6.xyz, R3, R6;\n" - "MUL R4.xyz, R5, R4;\n" - "ADD R3.xyz, -R3, c[8].x;\n" - "MAD R2.xyz, R2, R3, R0.w;\n" - "MUL R3.xyz, R0, c[8].y;\n" - "MAD R5.xyz, R0.w, R1, R6;\n" - "MAD R4.xyz, R0.w, R1, R4;\n" - "ADD R6.xyz, R4, -R5;\n" - "MUL R4.xyz, R1, c[8].w;\n" - "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R6, R5;\n" - "MAD R4.xyz, -R1, R2, R4;\n" - "SGE R3.xyz, R3, R0.w;\n" - "MUL R2.xyz, R1, R2;\n" - "ADD R2.w, -R1, c[8].x;\n" - "MAD R2.xyz, R3, R4, R2;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R0.x, -R0.w, c[8];\n" - "MAD R2.xyz, R1, R0.x, R2;\n" - "ADD R0.z, R0.w, R1.w;\n" - "MAD R2.w, -R0, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[6];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R2, -R1;\n" - "DP4 R0.x, R0, c[7];\n" - "MAD result.color, R0.x, R2, R1;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_DIFFERENCE = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.z;\n" - "MUL R1.xy, R0.zwzw, c[0];\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 2D;\n" - "ADD R2.xyz, R1, R0;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R1.xyz, R1, R0.w;\n" - "MIN R1.xyz, R1, R3;\n" - "MAD R2.xyz, -R1, c[8].x, R2;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_EXCLUSION = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.z;\n" - "MUL R1.xy, R0.zwzw, c[0];\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "TEX R1, R1, texture[2], 2D;\n" - "MUL R2.xyz, R1.w, R0;\n" - "MAD R3.xyz, R1, R0.w, R2;\n" - "MUL R2.xyz, R1, R0;\n" - "MAD R2.xyz, -R2, c[8].x, R3;\n" - "ADD R2.w, -R0, c[8].y;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[8].y;\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..6],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R1.xy, fragment.position, c[6];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MUL R2.xyz, R1, c[4].y;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "MUL R3.xyz, R0.w, R2;\n" - "MUL R2.xyz, R0, c[4].x;\n" - "MAD R2.xyz, R1.w, R2, R3;\n" - "ADD R2.w, -R1, c[7].x;\n" - "MUL R0.xyz, R0, c[5].y;\n" - "MAD R0.xyz, R2.w, R0, R2;\n" - "ADD R2.x, -R0.w, c[7];\n" - "MUL R1.xyz, R1, c[5].z;\n" - "MAD result.color.xyz, R2.x, R1, R0;\n" - "MUL R0.x, R0.w, R1.w;\n" - "MUL R0.z, R1.w, R2.x;\n" - "MUL R0.y, R0.w, R2.w;\n" - "DP3 result.color.w, R0, c[5];\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_MULTIPLY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2.x, -R1.w, c[5];\n" - "MUL R2.xyz, R0, R2.x;\n" - "MAD R0.xyz, R0, R1, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[5].x;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SCREEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..4] };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "ADD R2, R0, R1;\n" - "MAD result.color, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_OVERLAY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[5].y;\n" - "MUL R2.xyz, R2, c[5].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R3.xyz, R0, R2.w;\n" - "MUL R0.xyz, R0, R1;\n" - "ADD R2.w, -R0, c[5].y;\n" - "MAD R0.xyz, R0, c[5].x, R3;\n" - "MAD R0.xyz, R1, R2.w, R0;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "MUL R1.xyz, R1, c[5].x;\n" - "ADD R2.w, R0, R1;\n" - "ADD R2.xyz, R2, -R0;\n" - "SGE R1.xyz, R1, R1.w;\n" - "MAD result.color.xyz, R1, R2, R0;\n" - "MAD result.color.w, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_DARKEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[5].x;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_LIGHTEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "MAX R2.xyz, R2, R3;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[5].x;\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORDODGE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "MAX R1.x, R0.w, c[5].y;\n" - "RCP R1.x, R1.x;\n" - "MAD R3.xyz, -R0, R1.x, c[5].x;\n" - "MAX R3.xyz, R3, c[5].y;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.x, -R0.w, c[5];\n" - "MUL R2.xyz, R1, R2.x;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R1.xyz, R0.w, R1;\n" - "MAD R0.xyz, R0, R1.w, R1;\n" - "MUL R2.w, R0, R1;\n" - "RCP R3.x, R3.x;\n" - "RCP R3.y, R3.y;\n" - "RCP R3.z, R3.z;\n" - "MAD R3.xyz, R1, R3, R2;\n" - "MAD R2.xyz, R0.w, R1.w, R2;\n" - "ADD R1.x, R0.w, R1.w;\n" - "ADD R2.xyz, R2, -R3;\n" - "SGE R0.xyz, R0, R2.w;\n" - "MAD result.color.xyz, R0, R2, R3;\n" - "MAD result.color.w, -R0, R1, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORBURN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R2.xyz, -R0.w, R1.w, R3;\n" - "MUL R4.xyz, R0.w, R2;\n" - "MAX R2.xyz, R0, c[5].y;\n" - "MUL R5.xyz, R0, R2.w;\n" - "ADD R3.w, -R0, c[5].x;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R4, R2, R5;\n" - "MUL R4.xyz, R1, R3.w;\n" - "MAD R1.xyz, R1, R3.w, R2;\n" - "MAD R0.xyz, R0, R2.w, R4;\n" - "MUL R2.x, R0.w, R1.w;\n" - "ADD R2.w, R0, R1;\n" - "ADD R1.xyz, R1, -R0;\n" - "SGE R2.xyz, R3, R2.x;\n" - "MAD result.color.xyz, R2, R1, R0;\n" - "MAD result.color.w, -R0, R1, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_HARDLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "ADD R2.w, -R1, c[5].y;\n" - "ADD R3.xyz, R0.w, -R0;\n" - "ADD R2.xyz, R1.w, -R1;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[5].x;\n" - "MAD R2.xyz, R0.w, R1.w, -R2;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R4.xyz, R0, R2.w;\n" - "MUL R3.xyz, R0, R1;\n" - "MUL R0.xyz, R0, c[5].x;\n" - "ADD R2.w, -R0, c[5].y;\n" - "MAD R3.xyz, R3, c[5].x, R4;\n" - "MAD R3.xyz, R1, R2.w, R3;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R1.xyz, R1, -R3;\n" - "SGE R0.xyz, R0, R0.w;\n" - "MAD result.color.xyz, R0, R1, R3;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SOFTLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..4],\n" - " { 1, 2, 9.9999997e-006, 4 },\n" - " { 16, 12, 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "TEMP R6;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MUL R1.xy, fragment.position, c[4];\n" - "TEX R1, R1, texture[0], 2D;\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MAX R0.w, R1, c[5].z;\n" - "RCP R0.w, R0.w;\n" - "MUL R3.xyz, R1, R0.w;\n" - "MAD R2.xyz, R3, c[6].x, -c[6].y;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "MAD R4.xyz, R3, R2, c[6].z;\n" - "MAD R2.xyz, R0, c[5].y, -R0.w;\n" - "MUL R5.xyz, R1.w, R2;\n" - "MUL R6.xyz, R5, R4;\n" - "RSQ R2.w, R3.x;\n" - "RCP R4.x, R2.w;\n" - "RSQ R2.w, R3.y;\n" - "RSQ R3.w, R3.z;\n" - "RCP R4.y, R2.w;\n" - "RCP R4.z, R3.w;\n" - "ADD R4.xyz, -R3, R4;\n" - "MUL R6.xyz, R3, R6;\n" - "MUL R4.xyz, R5, R4;\n" - "ADD R3.xyz, -R3, c[5].x;\n" - "MAD R2.xyz, R2, R3, R0.w;\n" - "MUL R3.xyz, R0, c[5].y;\n" - "MAD R5.xyz, R0.w, R1, R6;\n" - "MAD R4.xyz, R0.w, R1, R4;\n" - "ADD R6.xyz, R4, -R5;\n" - "MUL R4.xyz, R1, c[5].w;\n" - "SGE R4.xyz, R4, R1.w;\n" - "MAD R4.xyz, R4, R6, R5;\n" - "MAD R4.xyz, -R1, R2, R4;\n" - "MUL R2.xyz, R1, R2;\n" - "SGE R3.xyz, R3, R0.w;\n" - "MAD R2.xyz, R3, R4, R2;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R0.x, R0.w, R1.w;\n" - "ADD R0.y, -R0.w, c[5].x;\n" - "MAD result.color.xyz, R1, R0.y, R2;\n" - "MAD result.color.w, -R0, R1, R0.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_DIFFERENCE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "MUL R2.xyz, R0, R1.w;\n" - "MUL R3.xyz, R0.w, R1;\n" - "ADD R0.xyz, R0, R1;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R1.x, R0.w, R1.w;\n" - "MAD result.color.xyz, -R2, c[5].x, R0;\n" - "MAD result.color.w, -R0, R1, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_EXCLUSION_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 2, 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R1, R0.zwzw, texture[0], 2D;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0, R0, texture[1], 2D;\n" - "MUL R2.xyz, R0.w, R1;\n" - "MAD R3.xyz, R0, R1.w, R2;\n" - "MUL R2.xyz, R0, R1;\n" - "MAD R2.xyz, -R2, c[5].x, R3;\n" - "ADD R2.w, -R1, c[5].y;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R0.w, R1.w;\n" - "ADD R2.y, -R0.w, c[5];\n" - "MAD result.color.xyz, R1, R2.y, R0;\n" - "MAD result.color.w, -R0, R1, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODE_BLEND_MODE_MASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..6] };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R1.xyz, R0, c[3];\n" - "RCP R0.z, R1.z;\n" - "MUL R1.xy, R1, R0.z;\n" - "ADD R0.xy, fragment.position, c[5];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[0], 2D;\n" - "DP4 R1.z, R0, c[6];\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R0, R1, texture[1], 2D;\n" - "MUL result.color, R0, R1.z;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODE_BLEND_MODE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[4] = { program.local[0..3] };\n" - "TEMP R0;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX result.color, R0, texture[0], 2D;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SIMPLE_PORTER_DUFF = - "!!ARBfp1.0\n" - "PARAM c[11] = { program.local[0..9],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, c[0].xyxy;\n" - "TEX R1.x, R0.zwzw, texture[2], 2D;\n" - "MUL R0.xy, fragment.position, c[7];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, -R1, c[10];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R2.xyz, R0, c[4].y;\n" - "MUL R3.xyz, R1.w, R2;\n" - "MUL R2.xyz, R1, c[4].x;\n" - "MAD R2.xyz, R0.w, R2, R3;\n" - "ADD R3.xy, fragment.position, c[8];\n" - "ADD R2.w, -R0, c[10].x;\n" - "MUL R1.xyz, R1, c[5].y;\n" - "MAD R2.xyz, R2.w, R1, R2;\n" - "MUL R1.xyz, R0, c[5].z;\n" - "ADD R3.z, -R1.w, c[10].x;\n" - "MAD R2.xyz, R3.z, R1, R2;\n" - "MUL R1.y, R1.w, R2.w;\n" - "MUL R1.x, R1.w, R0.w;\n" - "MUL R1.z, R0.w, R3;\n" - "DP3 R2.w, R1, c[5];\n" - "MUL R3.xy, R3, c[6];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[9];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_MULTIPLY = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.zw, R0.xyxy, c[0].xyxy;\n" - "TEX R1.x, R0.zwzw, texture[2], 2D;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, -R1, c[8];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "ADD R2.x, -R0.w, c[8];\n" - "MUL R2.xyz, R1, R2.x;\n" - "MAD R1.xyz, R1, R0, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SCREEN = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[2], 2D;\n" - "ADD R0.z, -R0.x, c[8].x;\n" - "ADD R3.xy, fragment.position, c[6];\n" - "MUL R1, fragment.color.primary, R0.z;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R2, R1, R0;\n" - "MAD R2, -R1, R0, R2;\n" - "MUL R3.xy, R3, c[4];\n" - "TEX R1, R3, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_OVERLAY = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[2], 2D;\n" - "ADD R0.x, -R0, c[8];\n" - "MUL R1, fragment.color.primary, R0.x;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "ADD R2.w, -R0, c[8].x;\n" - "ADD R3.xyz, R1.w, -R1;\n" - "ADD R2.xyz, R0.w, -R0;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[8].y;\n" - "MAD R2.xyz, R1.w, R0.w, -R2;\n" - "MUL R4.xyz, R1, R2.w;\n" - "MUL R3.xyz, R1, R0;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R3.xyz, R3, c[8].y, R4;\n" - "MAD R3.xyz, R0, R2.x, R3;\n" - "MAD R1.xyz, R0, R2.x, R1;\n" - "MUL R2.xyz, R0, c[8].y;\n" - "ADD R1.xyz, R1, -R3;\n" - "SGE R2.xyz, R2, R0.w;\n" - "MAD R2.xyz, R2, R1, R3;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DARKEN = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R1.x, R0, texture[2], 2D;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, -R1, c[8];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_LIGHTEN = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R1.x, R0, texture[2], 2D;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, -R1, c[8];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MAX R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORDODGE = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[2], 2D;\n" - "ADD R0.x, -R0, c[8];\n" - "MUL R1, fragment.color.primary, R0.x;\n" - "MAX R0.x, R1.w, c[8].y;\n" - "RCP R0.x, R0.x;\n" - "MAD R2.xyz, -R1, R0.x, c[8].x;\n" - "MAX R2.xyz, R2, c[8].y;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R2.w, -R1, c[8].x;\n" - "MUL R3.xyz, R0, R2.w;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MAD R4.xyz, R1, R2.w, R3;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.w, R1, R0;\n" - "MAD R1.xyz, R1, R0.w, R3;\n" - "SGE R1.xyz, R1, R2.w;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R3, R2, R4;\n" - "MAD R4.xyz, R1.w, R0.w, R4;\n" - "ADD R4.xyz, R4, -R2;\n" - "MAD R2.xyz, R1, R4, R2;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORBURN = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[2], 2D;\n" - "ADD R1.x, -R0, c[8];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "MUL R2.xyz, R1.w, R0;\n" - "MAD R3.xyz, R1, R0.w, R2;\n" - "MAD R2.xyz, -R1.w, R0.w, R3;\n" - "MUL R4.xyz, R1.w, R2;\n" - "MAX R2.xyz, R1, c[8].y;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MUL R5.xyz, R1, R2.w;\n" - "ADD R3.w, -R1, c[8].x;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R4, R2, R5;\n" - "MUL R4.xyz, R0, R3.w;\n" - "MAD R1.xyz, R1, R2.w, R4;\n" - "MUL R2.w, R1, R0;\n" - "MAD R2.xyz, R0, R3.w, R2;\n" - "ADD R2.xyz, R2, -R1;\n" - "SGE R3.xyz, R3, R2.w;\n" - "MAD R2.xyz, R3, R2, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_HARDLIGHT = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[2], 2D;\n" - "ADD R0.x, -R0, c[8];\n" - "MUL R1, fragment.color.primary, R0.x;\n" - "MUL R0.zw, fragment.position.xyxy, c[5].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "ADD R2.w, -R0, c[8].x;\n" - "ADD R3.xyz, R1.w, -R1;\n" - "ADD R2.xyz, R0.w, -R0;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[8].y;\n" - "MAD R2.xyz, R1.w, R0.w, -R2;\n" - "MUL R4.xyz, R1, R2.w;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "MUL R3.xyz, R1, R0;\n" - "ADD R2.w, -R1, c[8].x;\n" - "MAD R3.xyz, R3, c[8].y, R4;\n" - "MUL R1.xyz, R1, c[8].y;\n" - "SGE R1.xyz, R1, R1.w;\n" - "MAD R3.xyz, R0, R2.w, R3;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "ADD R2.xyz, R2, -R3;\n" - "MAD R2.xyz, R1, R2, R3;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SOFTLIGHT = - "!!ARBfp1.0\n" - "PARAM c[10] = { program.local[0..7],\n" - " { 1, 2, 9.9999997e-006, 4 },\n" - " { 16, 12, 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "TEMP R6;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R1.xyz, R0, c[3];\n" - "RCP R1.z, R1.z;\n" - "MUL R1.xy, R1, R1.z;\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1.x, R1, texture[2], 2D;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MAX R1.z, R0.w, c[8];\n" - "RCP R1.z, R1.z;\n" - "MUL R3.xyz, R0, R1.z;\n" - "MAD R2.xyz, R3, c[9].x, -c[9].y;\n" - "ADD R1.x, -R1, c[8];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MAD R4.xyz, R3, R2, c[9].z;\n" - "MAD R2.xyz, R1, c[8].y, -R1.w;\n" - "MUL R5.xyz, R0.w, R2;\n" - "MUL R6.xyz, R5, R4;\n" - "RSQ R2.w, R3.x;\n" - "RCP R4.x, R2.w;\n" - "RSQ R2.w, R3.y;\n" - "RSQ R3.w, R3.z;\n" - "RCP R4.y, R2.w;\n" - "RCP R4.z, R3.w;\n" - "ADD R4.xyz, -R3, R4;\n" - "MUL R6.xyz, R3, R6;\n" - "MUL R4.xyz, R5, R4;\n" - "ADD R3.xyz, -R3, c[8].x;\n" - "MAD R2.xyz, R2, R3, R1.w;\n" - "MUL R3.xyz, R1, c[8].y;\n" - "MAD R5.xyz, R1.w, R0, R6;\n" - "MAD R4.xyz, R1.w, R0, R4;\n" - "ADD R6.xyz, R4, -R5;\n" - "MUL R4.xyz, R0, c[8].w;\n" - "SGE R4.xyz, R4, R0.w;\n" - "MAD R4.xyz, R4, R6, R5;\n" - "MAD R4.xyz, -R0, R2, R4;\n" - "SGE R3.xyz, R3, R1.w;\n" - "MUL R2.xyz, R0, R2;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MAD R2.xyz, R3, R4, R2;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "ADD R1.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R1.x, R2;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DIFFERENCE = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R1.x, R0, texture[2], 2D;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "ADD R1.x, -R1, c[8];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "ADD R2.xyz, R1, R0;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R1.xyz, R1, R0.w;\n" - "MIN R1.xyz, R1, R3;\n" - "MAD R2.xyz, -R1, c[8].y, R2;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_EXCLUSION = - "!!ARBfp1.0\n" - "PARAM c[9] = { program.local[0..7],\n" - " { 1, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R1.x, R0, texture[2], 2D;\n" - "MUL R0.xy, fragment.position, c[5];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R1.x, -R1, c[8];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R2.xyz, R1.w, R0;\n" - "MAD R3.xyz, R1, R0.w, R2;\n" - "MUL R2.xyz, R1, R0;\n" - "MAD R2.xyz, -R2, c[8].y, R3;\n" - "ADD R2.w, -R0, c[8].x;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, -R1.w, c[8];\n" - "MAD R2.xyz, R0, R2.x, R1;\n" - "ADD R1.z, R1.w, R0.w;\n" - "MAD R2.w, -R1, R0, R1.z;\n" - "ADD R1.xy, fragment.position, c[6];\n" - "MUL R1.xy, R1, c[4];\n" - "TEX R1, R1, texture[1], 2D;\n" - "ADD R2, R2, -R0;\n" - "DP4 R1.x, R1, c[7];\n" - "MAD result.color, R1.x, R2, R0;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..6],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R1.x, R0, texture[1], 2D;\n" - "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "MUL R2.xyz, R0, c[4].y;\n" - "ADD R1.x, -R1, c[7];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R3.xyz, R1.w, R2;\n" - "MUL R2.xyz, R1, c[4].x;\n" - "MUL R0.xyz, R0, c[5].z;\n" - "MAD R2.xyz, R0.w, R2, R3;\n" - "ADD R2.w, -R0, c[7].x;\n" - "MUL R1.xyz, R1, c[5].y;\n" - "MAD R1.xyz, R2.w, R1, R2;\n" - "ADD R2.x, -R1.w, c[7];\n" - "MAD result.color.xyz, R2.x, R0, R1;\n" - "MUL R0.x, R1.w, R0.w;\n" - "MUL R0.z, R0.w, R2.x;\n" - "MUL R0.y, R1.w, R2.w;\n" - "DP3 result.color.w, R0, c[5];\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_MULTIPLY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R1.x, R0, texture[1], 2D;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "ADD R1.x, -R1, c[5];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "ADD R2.x, -R0.w, c[5];\n" - "MUL R2.xyz, R1, R2.x;\n" - "MAD R1.xyz, R1, R0, R2;\n" - "ADD R2.x, R1.w, R0.w;\n" - "ADD R2.y, -R1.w, c[5].x;\n" - "MAD result.color.xyz, R0, R2.y, R1;\n" - "MAD result.color.w, -R1, R0, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SCREEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[1], 2D;\n" - "ADD R1.x, -R0, c[5];\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "ADD R2, R1, R0;\n" - "MAD result.color, -R1, R0, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_OVERLAY_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[1], 2D;\n" - "ADD R0.x, -R0, c[5];\n" - "MUL R1, fragment.color.primary, R0.x;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "ADD R3.xyz, R1.w, -R1;\n" - "ADD R2.xyz, R0.w, -R0;\n" - "MUL R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[5].x;\n" - "MUL R2.xyz, R2, c[5].y;\n" - "MAD R2.xyz, R1.w, R0.w, -R2;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "MUL R3.xyz, R1, R2.w;\n" - "MUL R1.xyz, R1, R0;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R1.xyz, R1, c[5].y, R3;\n" - "MAD R1.xyz, R0, R2.w, R1;\n" - "MAD R2.xyz, R0, R2.w, R2;\n" - "MUL R0.xyz, R0, c[5].y;\n" - "ADD R2.w, R1, R0;\n" - "ADD R2.xyz, R2, -R1;\n" - "SGE R0.xyz, R0, R0.w;\n" - "MAD result.color.xyz, R0, R2, R1;\n" - "MAD result.color.w, -R1, R0, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DARKEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[1], 2D;\n" - "ADD R1.x, -R0, c[5];\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[5].x;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, R1.w, R0.w;\n" - "ADD R2.y, -R1.w, c[5].x;\n" - "MAD result.color.xyz, R0, R2.y, R1;\n" - "MAD result.color.w, -R1, R0, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_LIGHTEN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[1], 2D;\n" - "ADD R1.x, -R0, c[5];\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R2.xyz, R1, R0.w;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MAX R2.xyz, R2, R3;\n" - "ADD R2.w, -R0, c[5].x;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, R1.w, R0.w;\n" - "ADD R2.y, -R1.w, c[5].x;\n" - "MAD result.color.xyz, R0, R2.y, R1;\n" - "MAD result.color.w, -R1, R0, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORDODGE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1, 1e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[1], 2D;\n" - "ADD R0.x, -R0, c[5];\n" - "MUL R1, fragment.color.primary, R0.x;\n" - "MAX R0.x, R1.w, c[5].y;\n" - "RCP R0.x, R0.x;\n" - "MAD R3.xyz, -R1, R0.x, c[5].x;\n" - "MAX R3.xyz, R3, c[5].y;\n" - "MUL R0.xy, fragment.position, c[4];\n" - "TEX R0, R0, texture[0], 2D;\n" - "ADD R2.x, -R1.w, c[5];\n" - "MUL R2.xyz, R0, R2.x;\n" - "ADD R2.w, -R0, c[5].x;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "MUL R0.xyz, R1.w, R0;\n" - "RCP R3.x, R3.x;\n" - "RCP R3.y, R3.y;\n" - "RCP R3.z, R3.z;\n" - "MAD R3.xyz, R0, R3, R2;\n" - "MAD R0.xyz, R1, R0.w, R0;\n" - "MAD R2.xyz, R1.w, R0.w, R2;\n" - "MUL R2.w, R1, R0;\n" - "ADD R1.x, R1.w, R0.w;\n" - "ADD R2.xyz, R2, -R3;\n" - "SGE R0.xyz, R0, R2.w;\n" - "MAD result.color.xyz, R0, R2, R3;\n" - "MAD result.color.w, -R1, R0, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORBURN_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1, 9.9999997e-006 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[1], 2D;\n" - "ADD R1.x, -R0, c[5];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "MUL R2.xyz, R1.w, R0;\n" - "MAD R3.xyz, R1, R0.w, R2;\n" - "ADD R2.w, -R0, c[5].x;\n" - "MAD R2.xyz, -R1.w, R0.w, R3;\n" - "MUL R4.xyz, R1.w, R2;\n" - "MAX R2.xyz, R1, c[5].y;\n" - "MUL R5.xyz, R1, R2.w;\n" - "ADD R3.w, -R1, c[5].x;\n" - "RCP R2.x, R2.x;\n" - "RCP R2.y, R2.y;\n" - "RCP R2.z, R2.z;\n" - "MAD R2.xyz, R4, R2, R5;\n" - "MUL R4.xyz, R0, R3.w;\n" - "MAD R0.xyz, R0, R3.w, R2;\n" - "MAD R1.xyz, R1, R2.w, R4;\n" - "MUL R2.x, R1.w, R0.w;\n" - "ADD R2.w, R1, R0;\n" - "ADD R0.xyz, R0, -R1;\n" - "SGE R2.xyz, R3, R2.x;\n" - "MAD result.color.xyz, R2, R0, R1;\n" - "MAD result.color.w, -R1, R0, R2;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_HARDLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[1], 2D;\n" - "ADD R0.x, -R0, c[5];\n" - "MUL R1, fragment.color.primary, R0.x;\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "ADD R2.w, -R0, c[5].x;\n" - "ADD R3.xyz, R1.w, -R1;\n" - "ADD R2.xyz, R0.w, -R0;\n" - "MUL R2.xyz, R2, R3;\n" - "MUL R2.xyz, R2, c[5].y;\n" - "MAD R2.xyz, R1.w, R0.w, -R2;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "MUL R4.xyz, R1, R2.w;\n" - "MUL R3.xyz, R1, R0;\n" - "MUL R1.xyz, R1, c[5].y;\n" - "ADD R2.w, -R1, c[5].x;\n" - "MAD R3.xyz, R3, c[5].y, R4;\n" - "MAD R3.xyz, R0, R2.w, R3;\n" - "MAD R0.xyz, R0, R2.w, R2;\n" - "ADD R2.x, R1.w, R0.w;\n" - "ADD R0.xyz, R0, -R3;\n" - "SGE R1.xyz, R1, R1.w;\n" - "MAD result.color.xyz, R1, R0, R3;\n" - "MAD result.color.w, -R1, R0, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SOFTLIGHT_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[7] = { program.local[0..4],\n" - " { 1, 2, 9.9999997e-006, 4 },\n" - " { 16, 12, 3 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "TEMP R4;\n" - "TEMP R5;\n" - "TEMP R6;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R1.xyz, R0, c[3];\n" - "RCP R1.z, R1.z;\n" - "MUL R1.xy, R1, R1.z;\n" - "MUL R1.xy, R1, c[0];\n" - "TEX R1.x, R1, texture[1], 2D;\n" - "MUL R0.xy, fragment.position, c[4];\n" - "TEX R0, R0, texture[0], 2D;\n" - "MAX R1.z, R0.w, c[5];\n" - "RCP R1.z, R1.z;\n" - "MUL R3.xyz, R0, R1.z;\n" - "MAD R2.xyz, R3, c[6].x, -c[6].y;\n" - "ADD R1.x, -R1, c[5];\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MAD R4.xyz, R3, R2, c[6].z;\n" - "MAD R2.xyz, R1, c[5].y, -R1.w;\n" - "MUL R5.xyz, R0.w, R2;\n" - "MUL R6.xyz, R5, R4;\n" - "RSQ R2.w, R3.x;\n" - "RCP R4.x, R2.w;\n" - "RSQ R2.w, R3.y;\n" - "RSQ R3.w, R3.z;\n" - "RCP R4.y, R2.w;\n" - "RCP R4.z, R3.w;\n" - "ADD R4.xyz, -R3, R4;\n" - "MUL R6.xyz, R3, R6;\n" - "MUL R4.xyz, R5, R4;\n" - "ADD R3.xyz, -R3, c[5].x;\n" - "MAD R2.xyz, R2, R3, R1.w;\n" - "MUL R3.xyz, R1, c[5].y;\n" - "MAD R5.xyz, R1.w, R0, R6;\n" - "MAD R4.xyz, R1.w, R0, R4;\n" - "ADD R6.xyz, R4, -R5;\n" - "MUL R4.xyz, R0, c[5].w;\n" - "SGE R4.xyz, R4, R0.w;\n" - "MAD R4.xyz, R4, R6, R5;\n" - "MAD R4.xyz, -R0, R2, R4;\n" - "MUL R2.xyz, R0, R2;\n" - "SGE R3.xyz, R3, R1.w;\n" - "MAD R2.xyz, R3, R4, R2;\n" - "ADD R2.w, -R0, c[5].x;\n" - "MAD R2.xyz, R1, R2.w, R2;\n" - "ADD R1.x, R1.w, R0.w;\n" - "ADD R1.y, -R1.w, c[5].x;\n" - "MAD result.color.xyz, R0, R1.y, R2;\n" - "MAD result.color.w, -R1, R0, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DIFFERENCE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[1], 2D;\n" - "ADD R1.x, -R0, c[5];\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R3.xyz, R1.w, R0;\n" - "MUL R2.xyz, R1, R0.w;\n" - "ADD R0.xyz, R1, R0;\n" - "MIN R2.xyz, R2, R3;\n" - "ADD R1.x, R1.w, R0.w;\n" - "MAD result.color.xyz, -R2, c[5].y, R0;\n" - "MAD result.color.w, -R1, R0, R1.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_EXCLUSION_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[6] = { program.local[0..4],\n" - " { 1, 2 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "TEMP R2;\n" - "TEMP R3;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[1], 2D;\n" - "ADD R1.x, -R0, c[5];\n" - "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n" - "TEX R0, R0.zwzw, texture[0], 2D;\n" - "MUL R1, fragment.color.primary, R1.x;\n" - "MUL R2.xyz, R1.w, R0;\n" - "MAD R3.xyz, R1, R0.w, R2;\n" - "MUL R2.xyz, R1, R0;\n" - "MAD R2.xyz, -R2, c[5].y, R3;\n" - "ADD R2.w, -R0, c[5].x;\n" - "MAD R1.xyz, R1, R2.w, R2;\n" - "ADD R2.x, R1.w, R0.w;\n" - "ADD R2.y, -R1.w, c[5].x;\n" - "MAD result.color.xyz, R0, R2.y, R1;\n" - "MAD result.color.w, -R1, R0, R2.x;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODE_BLEND_MODE_MASK = - "!!ARBfp1.0\n" - "PARAM c[8] = { program.local[0..6],\n" - " { 1 } };\n" - "TEMP R0;\n" - "TEMP R1;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.zw, R0.xyxy, R0.z;\n" - "MUL R0.zw, R0, c[0].xyxy;\n" - "TEX R1.x, R0.zwzw, texture[1], 2D;\n" - "ADD R0.xy, fragment.position, c[5];\n" - "MUL R0.xy, R0, c[4];\n" - "TEX R0, R0, texture[0], 2D;\n" - "DP4 R1.y, R0, c[6];\n" - "ADD R1.x, -R1, c[7];\n" - "MUL R0, fragment.color.primary, R1.x;\n" - "MUL result.color, R0, R1.y;\n" - "END\n" - ; - -static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODE_BLEND_MODE_NOMASK = - "!!ARBfp1.0\n" - "PARAM c[5] = { program.local[0..3],\n" - " { 1 } };\n" - "TEMP R0;\n" - "MUL R0.xyz, fragment.position.y, c[2];\n" - "MAD R0.xyz, fragment.position.x, c[1], R0;\n" - "ADD R0.xyz, R0, c[3];\n" - "RCP R0.z, R0.z;\n" - "MUL R0.xy, R0, R0.z;\n" - "MUL R0.xy, R0, c[0];\n" - "TEX R0.x, R0, texture[0], 2D;\n" - "ADD R0.x, -R0, c[4];\n" - "MUL result.color, fragment.color.primary, R0.x;\n" - "END\n" - ; - -static const char *mask_fragment_program_sources[num_fragment_masks] = { - FragmentProgram_FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, - FragmentProgram_FRAGMENT_PROGRAM_MASK_ELLIPSE_AA, -}; - -static const char *painter_fragment_program_sources[num_fragment_brushes][num_fragment_composition_modes] = { - { - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SIMPLE_PORTER_DUFF, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_MULTIPLY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SCREEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_OVERLAY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_DARKEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_LIGHTEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORDODGE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORBURN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_HARDLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SOFTLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_DIFFERENCE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_EXCLUSION, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_MULTIPLY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SCREEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_OVERLAY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_DARKEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_LIGHTEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORDODGE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORBURN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_HARDLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SOFTLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_DIFFERENCE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_EXCLUSION_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE_BLEND_MODE_MASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE_BLEND_MODE_NOMASK, - }, - { - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_MULTIPLY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SCREEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_OVERLAY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DARKEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_LIGHTEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORDODGE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORBURN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_HARDLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SOFTLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DIFFERENCE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_EXCLUSION, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_MULTIPLY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SCREEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_OVERLAY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DARKEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_LIGHTEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORDODGE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORBURN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_HARDLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SOFTLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DIFFERENCE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_EXCLUSION_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODE_BLEND_MODE_MASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODE_BLEND_MODE_NOMASK, - }, - { - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_MULTIPLY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SCREEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_OVERLAY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DARKEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_LIGHTEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORDODGE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORBURN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_HARDLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SOFTLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DIFFERENCE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_EXCLUSION, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_MULTIPLY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SCREEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_OVERLAY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DARKEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_LIGHTEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORDODGE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORBURN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_HARDLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SOFTLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DIFFERENCE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_EXCLUSION_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODE_BLEND_MODE_MASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODE_BLEND_MODE_NOMASK, - }, - { - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SIMPLE_PORTER_DUFF, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_MULTIPLY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SCREEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_OVERLAY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_DARKEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_LIGHTEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORDODGE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORBURN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_HARDLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SOFTLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_DIFFERENCE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_EXCLUSION, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_MULTIPLY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SCREEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_OVERLAY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_DARKEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_LIGHTEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORDODGE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_COLORBURN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_HARDLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SOFTLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_DIFFERENCE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_EXCLUSION_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODE_BLEND_MODE_MASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODE_BLEND_MODE_NOMASK, - }, - { - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SIMPLE_PORTER_DUFF, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_MULTIPLY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SCREEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_OVERLAY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_DARKEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_LIGHTEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORDODGE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORBURN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_HARDLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SOFTLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_DIFFERENCE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_EXCLUSION, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_MULTIPLY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SCREEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_OVERLAY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_DARKEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_LIGHTEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORDODGE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_COLORBURN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_HARDLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SOFTLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_DIFFERENCE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_EXCLUSION_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODE_BLEND_MODE_MASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODE_BLEND_MODE_NOMASK, - }, - { - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SIMPLE_PORTER_DUFF, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_MULTIPLY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SCREEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_OVERLAY, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DARKEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_LIGHTEN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORDODGE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORBURN, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_HARDLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SOFTLIGHT, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DIFFERENCE, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_EXCLUSION, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SIMPLE_PORTER_DUFF_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_MULTIPLY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SCREEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_OVERLAY_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DARKEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_LIGHTEN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORDODGE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_COLORBURN_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_HARDLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SOFTLIGHT_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DIFFERENCE_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_EXCLUSION_NOMASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODE_BLEND_MODE_MASK, - FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODE_BLEND_MODE_NOMASK, - }, -}; - -static int painter_variable_locations[num_fragment_brushes][num_fragment_composition_modes][num_fragment_variables] = { - { - { -1, -1, -1, 2, -1, 0, 5, -1, 1, 3, 1, 0, -1, 4, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 3, -1, -1, 1, 1, 0, -1, 2, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, 0, -1, -1, 1, 2, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, 0, -1, -1, 2, -1, -1, -1, 0, -1, -1, 1, -1, -1, -1, -1, -1, }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - }, - { - { -1, -1, 3, 7, 4, 5, 10, -1, 6, 8, 1, 0, 2, 9, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 8, -1, -1, 6, 1, 0, 2, 7, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, 5, -1, -1, 6, 7, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, 5, -1, 0, 1, -1, -1, 1, 0, 2, -1, }, - { -1, -1, 3, 5, 4, -1, 7, -1, -1, -1, 0, -1, 1, 6, -1, 1, 0, 2, -1, }, - { -1, -1, 3, -1, 4, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 1, 0, 2, -1, }, - }, - { - { -1, -1, 2, 6, 3, 4, 9, -1, 5, 7, 1, 0, 2, 8, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, 4, -1, -1, 5, 6, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, 0, }, - { -1, -1, 2, 4, 3, -1, 6, -1, -1, -1, 0, -1, 1, 5, -1, -1, -1, 1, 0, }, - { -1, -1, 2, -1, 3, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, 1, 0, }, - }, - { - { -1, 0, 2, 6, 3, 4, 9, -1, 5, 7, 1, 0, 2, 8, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, 2, 6, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, 4, -1, -1, 5, 6, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 1, -1, }, - { -1, 0, 2, 4, 3, -1, 6, -1, -1, -1, 0, -1, 1, 5, -1, -1, -1, 1, -1, }, - { -1, 0, 2, -1, 3, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, 1, -1, }, - }, - { - { 2, -1, 2, 6, 3, 4, 9, -1, 5, 7, 1, 0, -1, 8, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, 4, -1, -1, 5, 6, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, 4, 3, -1, 6, -1, -1, -1, 0, -1, -1, 5, 0, -1, -1, 1, -1, }, - { 0, -1, 2, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 1, -1, }, - }, - { - { 2, -1, 2, 6, 3, 4, 9, -1, 5, 7, 1, 0, -1, 8, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 2, -1, 2, 4, 3, -1, 7, -1, -1, 5, 1, 0, -1, 6, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, 4, -1, -1, 5, 6, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, -1, 3, -1, -1, -1, -1, 4, -1, 0, -1, -1, 0, -1, -1, 1, -1, }, - { 1, -1, 2, 4, 3, -1, 6, -1, -1, -1, 0, -1, -1, 5, 0, -1, -1, 1, -1, }, - { 0, -1, 2, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 1, -1, }, - }, -}; - -static int mask_variable_locations[num_fragment_masks][num_fragment_variables] = { - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, - { -1, -1, 1, -1, 2, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, }, -}; - -#endif diff --git a/src/opengl/util/generator.cpp b/src/opengl/util/generator.cpp deleted file mode 100644 index 3d12446842..0000000000 --- a/src/opengl/util/generator.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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, Nokia gives you certain additional -** rights. These rights are described in the Nokia 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -QT_USE_NAMESPACE - -#define TAB " " - -typedef QPair QStringPair; - -QString readSourceFile(const QString &sourceFile, bool fragmentProgram = false) -{ - QFile file(sourceFile); - - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << "Missing source file" << sourceFile; - exit(0); - } - - QString source; - - QTextStream in(&file); - while (!in.atEnd()) { - QString line = in.readLine(); - - if (fragmentProgram && line[0] == '#' && !line.startsWith("#var")) - continue; - - if (fragmentProgram) - source.append(" \""); - - source.append(line); - - if (fragmentProgram) - source.append("\\n\""); - - source.append('\n'); - } - - if (fragmentProgram) - source.append(" ;\n"); - - return source; -} - -QList readConf(const QString &confFile) -{ - QFile file(confFile); - - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << "Missing file" << confFile; - exit(0); - } - - QList result; - - QTextStream in(&file); - while (!in.atEnd()) { - QString line = in.readLine(); - - if (line.startsWith('#')) - continue; - - QTextStream lineStream(&line); - - QString enumerator; - QString sourceFile; - - lineStream >> enumerator; - - if (lineStream.atEnd()) { - qDebug() << "Error in file" << confFile << '(' << enumerator << ')'; - exit(0); - } - - lineStream >> sourceFile; - - result << QStringPair(enumerator, readSourceFile(sourceFile)); - } - - return result; -} - -QString compileSource(const QString &source) -{ - { - QFile tempSourceFile("__tmp__.glsl"); - if (!tempSourceFile.open(QIODevice::WriteOnly | QIODevice::Text)) { - qDebug() << "Failed opening __tmp__.glsl"; - exit(0); - } - - QTextStream out(&tempSourceFile); - out << source; - } - - if (std::system("cgc -quiet -oglsl -profile arbfp1 __tmp__.glsl >__tmp__.frag") == -1) { - qDebug() << "Failed running cgc"; - exit(0); - } - - return readSourceFile("__tmp__.frag", true); -} - -QString getWord(QString line, int word) -{ - QTextStream in(&line); - - QString result; - - for (int i = 0; i < word; ++i) - in >> result; - - return result; -} - -static int toInt(const QByteArray &str) -{ - int value = 0; - - for (int i = 0; i < str.size(); ++i) { - if (str[i] < '0' || str[i] > '9') - break; - - value *= 10; - value += (str[i] - '0'); - } - - return value; -} -QList getLocations(const QSet &variables, QString source) -{ - QTextStream in(&source); - - QMap locations; - - foreach (QString variable, variables) - locations[variable] = -1; - - while (!in.atEnd()) { - QString line = in.readLine().trimmed(); - - line = line.right(line.size() - 1); - - if (line.startsWith("#var")) { - QByteArray temp; - QByteArray name; - - QTextStream lineStream(&line); - - lineStream >> temp >> temp >> name; - - int location = -1; - - while (!lineStream.atEnd()) { - lineStream >> temp; - - if (temp.startsWith("c[")) { - location = toInt(temp.right(temp.size() - 2)); - break; - } - - if (temp == "texunit") { - lineStream >> temp; - location = toInt(temp); - break; - } - } - - locations[name] = location; - } - } - - QList result; - - foreach (QString variable, variables) - result << locations[variable]; - - return result; -} - -// remove #var statements -QString trimmed(QString source) -{ - QTextStream in(&source); - - QString result; - - while (!in.atEnd()) { - QString line = in.readLine(); - if (!line.trimmed().startsWith("\"#")) - result += line + '\n'; - } - - return result; -} - -void writeVariablesEnum(QTextStream &out, const char *name, const QSet &s) -{ - out << "enum " << name << " {"; - QSet::const_iterator it = s.begin(); - if (it != s.end()) { - out << "\n" TAB "VAR_" << it->toUpper(); - for (++it; it != s.end(); ++it) - out << ",\n" TAB "VAR_" << it->toUpper(); - } - out << "\n};\n\n"; -} - -void writeTypesEnum(QTextStream &out, const char *name, const QList &s) -{ - out << "enum " << name << " {"; - QList::const_iterator it = s.begin(); - if (it != s.end()) { - out << "\n" TAB << it->first; - for (++it; it != s.end(); ++it) - out << ",\n" TAB << it->first; - } - out << "\n};\n\n"; -} - -void writeIncludeFile(const QSet &variables, - const QList &brushes, - const QList &compositionModes, - const QList &masks, - const QMap > &compiled) -{ - QFile includeFile("fragmentprograms_p.h"); - if (!includeFile.open(QIODevice::WriteOnly | QIODevice::Text)) { - qDebug() << "Failed opening fragmentprograms_p.h"; - exit(0); - } - - QTextStream out(&includeFile); - - QLatin1String tab(TAB); - - out << "/****************************************************************************\n" - "**\n" - "** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).\n" - "** All rights reserved.\n" - "** Contact: Nokia Corporation (qt-info@nokia.com)\n" - "**\n" - "** This file is part of the QtOpenGL module of the Qt Toolkit.\n" - "**\n" - "** $QT_BEGIN_LICENSE:LGPL$\n" - "** GNU Lesser General Public License Usage\n" - "** This file may be used under the terms of the GNU Lesser General Public\n" - "** License version 2.1 as published by the Free Software Foundation and\n" - "** appearing in the file LICENSE.LGPL included in the packaging of this\n" - "** file. Please review the following information to ensure the GNU Lesser\n" - "** General Public License version 2.1 requirements will be met:\n" - "** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.\n" - "**\n" - "** In addition, as a special exception, Nokia gives you certain additional\n" - "** rights. These rights are described in the Nokia Qt LGPL Exception\n" - "** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.\n" - "**\n" - "** GNU General Public License Usage\n" - "** Alternatively, this file may be used under the terms of the GNU General\n" - "** Public License version 3.0 as published by the Free Software Foundation\n" - "** and appearing in the file LICENSE.GPL included in the packaging of this\n" - "** file. Please review the following information to ensure the GNU General\n" - "** Public License version 3.0 requirements will be met:\n" - "** http://www.gnu.org/copyleft/gpl.html.\n" - "**\n" - "** Other Usage\n" - "** Alternatively, this file may be used in accordance with the terms and\n" - "** conditions contained in a signed written agreement between you and Nokia.\n" - "**\n" - "**\n" - "**\n" - "**\n" - "**\n" - "** $QT_END_LICENSE$\n" - "**\n" - "****************************************************************************/\n" - "\n" - "#ifndef FRAGMENTPROGRAMS_P_H\n" - "#define FRAGMENTPROGRAMS_P_H\n" - "\n" - "//\n" - "// W A R N I N G\n" - "// -------------\n" - "//\n" - "// This file is not part of the Qt API. It exists purely as an\n" - "// implementation detail. This header file may change from version to\n" - "// version without notice, or even be removed.\n" - "//\n" - "// We mean it.\n" - "//\n" - "\n"; - - writeVariablesEnum(out, "FragmentVariable", variables); - writeTypesEnum(out, "FragmentBrushType", brushes); - writeTypesEnum(out, "FragmentCompositionModeType", compositionModes); - writeTypesEnum(out, "FragmentMaskType", masks); - - out << "static const unsigned int num_fragment_variables = " << variables.size() << ";\n\n"; - out << "static const unsigned int num_fragment_brushes = " << brushes.size() << ";\n"; - out << "static const unsigned int num_fragment_composition_modes = " << compositionModes.size() << ";\n"; - out << "static const unsigned int num_fragment_masks = " << masks.size() << ";\n\n"; - - foreach (QStringPair mask, masks) { - const QString compiledSource = compiled[mask.first]["MASK__"]; - - out << "static const char *FragmentProgram_" << mask.first << " =\n" - << trimmed(compiledSource) - << '\n'; - } - - foreach (QStringPair brush, brushes) { - foreach (QStringPair mode, compositionModes) { - const QString compiledSource = compiled[brush.first][mode.first]; - - out << "static const char *FragmentProgram_" << brush.first << '_' << mode.first << " =\n" - << trimmed(compiledSource) - << '\n'; - } - } - - out << "static const char *mask_fragment_program_sources[num_fragment_masks] = {\n"; - foreach (QStringPair mask, masks) - out << tab << "FragmentProgram_" << mask.first << ",\n"; - out << "};\n\n"; - - out << "static const char *painter_fragment_program_sources[num_fragment_brushes][num_fragment_composition_modes] = {\n"; - foreach (QStringPair brush, brushes) { - out << tab << "{\n"; - - foreach (QStringPair mode, compositionModes) - out << tab << tab << "FragmentProgram_" << brush.first << '_' << mode.first << ",\n"; - - out << tab << "},\n"; - } - out << "};\n\n"; - - out << "static int painter_variable_locations[num_fragment_brushes][num_fragment_composition_modes][num_fragment_variables] = {\n"; - foreach (QStringPair brush, brushes) { - out << tab << "{\n"; - - foreach (QStringPair mode, compositionModes) { - out << tab << tab << "{ "; - - QList locations = getLocations(variables, compiled[brush.first][mode.first]); - - foreach (int location, locations) - out << location << ", "; - - out << "},\n"; - } - - out << tab << "},\n"; - } - out << "};\n\n"; - - out << "static int mask_variable_locations[num_fragment_masks][num_fragment_variables] = {\n"; - foreach (QStringPair mask, masks) { - out << tab << "{ "; - - QList locations = getLocations(variables, compiled[mask.first]["MASK__"]); - - foreach (int location, locations) - out << location << ", "; - - out << "},\n"; - } - out << "};\n\n"; - out << "#endif\n"; -} - -QList getVariables(QString program) -{ - QList result; - - QTextStream in(&program); - while (!in.atEnd()) { - QString line = in.readLine(); - - if (line.startsWith("uniform")) { - QString word = getWord(line, 3); - result << word.left(word.size() - 1); - } else if (line.startsWith("#include")) { - QString file = getWord(line, 2); - result << getVariables(readSourceFile(file.mid(1, file.size() - 2))); - } - } - - return result; -} - -int main() -{ - QList brushes = readConf(QLatin1String("brushes.conf")); - QList compositionModes = readConf(QLatin1String("composition_modes.conf")); - QList masks = readConf(QLatin1String("masks.conf")); - - QString painterSource = readSourceFile("painter.glsl"); - QString painterNoMaskSource = readSourceFile("painter_nomask.glsl"); - QString fastPainterSource = readSourceFile("fast_painter.glsl"); - QString brushPainterSource = readSourceFile("brush_painter.glsl"); - - QSet variables; - - QList programs[3] = { brushes, compositionModes, masks }; - - for (int i = 0; i < 3; ++i) - foreach (QStringPair value, programs[i]) - variables += QSet::fromList(getVariables(value.second)); - - variables += QSet::fromList(getVariables(painterSource)); - variables += QSet::fromList(getVariables(fastPainterSource)); - - QMap > compiled; - - foreach (QStringPair brush, brushes) { - foreach (QStringPair mode, compositionModes) { - QString combinedSource = brush.second + mode.second + painterSource; - compiled[brush.first][mode.first] = compileSource(combinedSource); - - combinedSource = brush.second + mode.second + painterNoMaskSource; - compiled[brush.first][mode.first + "_NOMASK"] = compileSource(combinedSource); - } - - QString fastSource = brush.second + fastPainterSource; - QString brushSource = brush.second + brushPainterSource; - - compiled[brush.first]["COMPOSITION_MODE_BLEND_MODE_MASK"] = compileSource(fastSource); - compiled[brush.first]["COMPOSITION_MODE_BLEND_MODE_NOMASK"] = compileSource(brushSource); - } - - QList temp; - - foreach (QStringPair mode, compositionModes) - temp << QStringPair(mode.first + "_NOMASK", mode.second); - - compositionModes += temp; - - compositionModes << QStringPair("COMPOSITION_MODE_BLEND_MODE_MASK", "") - << QStringPair("COMPOSITION_MODE_BLEND_MODE_NOMASK", ""); - - foreach (QStringPair mask, masks) - compiled[mask.first]["MASK__"] = compileSource(mask.second); - - writeIncludeFile(variables, brushes, compositionModes, masks, compiled); - - return 0; -} - -QT_END_NAMESPACE diff --git a/src/opengl/util/generator.pro b/src/opengl/util/generator.pro deleted file mode 100644 index ac71934ecf..0000000000 --- a/src/opengl/util/generator.pro +++ /dev/null @@ -1,13 +0,0 @@ -###################################################################### -# Automatically generated by qmake (2.01a) Thu Oct 19 11:03:24 2006 -###################################################################### - -TEMPLATE = app -TARGET = generator -DEPENDPATH += . -INCLUDEPATH += . - -# Input -SOURCES += generator.cpp - -CONFIG += console diff --git a/src/opengl/util/glsl_to_include.sh b/src/opengl/util/glsl_to_include.sh deleted file mode 100755 index c97239bfdd..0000000000 --- a/src/opengl/util/glsl_to_include.sh +++ /dev/null @@ -1,73 +0,0 @@ -#! /bin/sh -############################################################################# -## -## Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -## All rights reserved. -## Contact: Nokia Corporation (qt-info@nokia.com) -## -## This file is the build configuration utility of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:LGPL$ -## GNU Lesser General Public License Usage -## 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, Nokia gives you certain additional -## rights. These rights are described in the Nokia 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. -## -## Other Usage -## Alternatively, this file may be used in accordance with the terms and -## conditions contained in a signed written agreement between you and Nokia. -## -## -## -## -## -## $QT_END_LICENSE$ -## -############################################################################# - -# Compile a .glsl file to a file that can be included in a C++ program -USAGE="Usage: $0 " -CGC=cgc -CGC_PROFILE=arbfp1 - -if test $# -ne 1 -then - echo $USAGE - exit 1 -fi - -GLSL_FILE=$1 -FRAG_FILE=`basename $1 .glsl`.frag -#GLSL_INC_FILE=`basename $1 .glsl`.glsl_quoted - -echo "// Generated by src/opengl/util/$0 from $1" > $FRAG_FILE -$CGC -quiet -oglsl -profile $CGC_PROFILE $GLSL_FILE | while read line -do - if test `echo $line | cut -c1` != "#" - then - echo -e \"$line\" >> $FRAG_FILE - fi -done -echo "; // Generated by src/opengl/util/$0 from $1" >> $FRAG_FILE - -#echo "// Generated by src/opengl/util/$0 from $1" > $GLSL_INC_FILE -#cat $GLSL_FILE | while read line -#do -# printf \"%s\\\\n\"\\n "$line" >> $GLSL_INC_FILE -#done -#echo "; // Generated by src/opengl/util/$0 from $1" >> $GLSL_INC_FILE diff --git a/src/opengl/util/linear_brush.glsl b/src/opengl/util/linear_brush.glsl deleted file mode 100644 index 90a4440a99..0000000000 --- a/src/opengl/util/linear_brush.glsl +++ /dev/null @@ -1,22 +0,0 @@ -uniform sampler1D palette; -uniform vec3 linear; -uniform vec3 inv_matrix_m0; -uniform vec3 inv_matrix_m1; -uniform vec3 inv_matrix_m2; - -vec4 brush() -{ - mat3 mat; - - mat[0] = inv_matrix_m0; - mat[1] = inv_matrix_m1; - mat[2] = inv_matrix_m2; - - vec3 hcoords = mat * vec3(gl_FragCoord.xy, 1); - vec2 A = hcoords.xy / hcoords.z; - - float val = dot(linear.xy, A) * linear.z; - - return texture1D(palette, val); -} - diff --git a/src/opengl/util/masks.conf b/src/opengl/util/masks.conf deleted file mode 100644 index d853d0b6e9..0000000000 --- a/src/opengl/util/masks.conf +++ /dev/null @@ -1,2 +0,0 @@ -FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA trap_exact_aa.glsl -FRAGMENT_PROGRAM_MASK_ELLIPSE_AA ellipse_aa.glsl diff --git a/src/opengl/util/meego/shader-cache-introspector.pro b/src/opengl/util/meego/shader-cache-introspector.pro deleted file mode 100644 index 520e9a5108..0000000000 --- a/src/opengl/util/meego/shader-cache-introspector.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app - -SOURCES += main.cpp - -TARGET = shader-cache-introspector - -QT = core diff --git a/src/opengl/util/painter.glsl b/src/opengl/util/painter.glsl deleted file mode 100644 index b990234778..0000000000 --- a/src/opengl/util/painter.glsl +++ /dev/null @@ -1,21 +0,0 @@ -uniform sampler2D dst_texture; -uniform sampler2D mask_texture; -uniform vec2 inv_mask_size; -uniform vec2 inv_dst_size; -uniform vec2 mask_offset; -uniform vec4 mask_channel; - -float mask() -{ - return dot(mask_channel, texture2D(mask_texture, (gl_FragCoord.xy + mask_offset) * inv_mask_size)); -} - -void main() -{ - vec4 dst = texture2D(dst_texture, gl_FragCoord.xy * inv_dst_size); - - // combine clip and coverage channels - float mask_alpha = mask(); - - gl_FragColor = mix(dst, composite(brush(), dst), mask_alpha); -} diff --git a/src/opengl/util/painter_nomask.glsl b/src/opengl/util/painter_nomask.glsl deleted file mode 100644 index af5ad6505f..0000000000 --- a/src/opengl/util/painter_nomask.glsl +++ /dev/null @@ -1,9 +0,0 @@ -uniform sampler2D dst_texture; -uniform vec2 inv_dst_size; - -void main() -{ - vec4 dst = texture2D(dst_texture, gl_FragCoord.xy * inv_dst_size); - - gl_FragColor = composite(brush(), dst); -} diff --git a/src/opengl/util/pattern_brush.glsl b/src/opengl/util/pattern_brush.glsl deleted file mode 100644 index 31702b887c..0000000000 --- a/src/opengl/util/pattern_brush.glsl +++ /dev/null @@ -1,23 +0,0 @@ -uniform sampler2D brush_texture; -uniform vec2 inv_brush_texture_size; -uniform vec3 inv_matrix_m0; -uniform vec3 inv_matrix_m1; -uniform vec3 inv_matrix_m2; - -vec4 brush() -{ - mat3 mat; - - mat[0] = inv_matrix_m0; - mat[1] = inv_matrix_m1; - mat[2] = inv_matrix_m2; - - vec3 hcoords = mat * vec3(gl_FragCoord.xy, 1); - vec2 coords = hcoords.xy / hcoords.z; - - coords *= inv_brush_texture_size; - - float alpha = 1.0 - texture2D(brush_texture, coords).r; - - return gl_Color * alpha; -} diff --git a/src/opengl/util/radial_brush.glsl b/src/opengl/util/radial_brush.glsl deleted file mode 100644 index 84bec62e65..0000000000 --- a/src/opengl/util/radial_brush.glsl +++ /dev/null @@ -1,28 +0,0 @@ -uniform sampler1D palette; -uniform vec2 fmp; -uniform float fmp2_m_radius2; -uniform vec3 inv_matrix_m0; -uniform vec3 inv_matrix_m1; -uniform vec3 inv_matrix_m2; - -vec4 brush() -{ - mat3 mat; - - mat[0] = inv_matrix_m0; - mat[1] = inv_matrix_m1; - mat[2] = inv_matrix_m2; - - vec3 hcoords = mat * vec3(gl_FragCoord.xy, 1); - vec2 A = hcoords.xy / hcoords.z; - vec2 B = fmp; - - float a = fmp2_m_radius2; - float b = 2.0*dot(A, B); - float c = -dot(A, A); - - float val = (-b + sqrt(b*b - 4.0*a*c)) / (2.0*a); - - return texture1D(palette, val); -} - diff --git a/src/opengl/util/simple_porter_duff.glsl b/src/opengl/util/simple_porter_duff.glsl deleted file mode 100644 index 4cb0599ac5..0000000000 --- a/src/opengl/util/simple_porter_duff.glsl +++ /dev/null @@ -1,16 +0,0 @@ -uniform vec2 porterduff_ab; -uniform vec3 porterduff_xyz; - -vec4 composite(vec4 src, vec4 dst) -{ - vec4 result; - - result.xyz = porterduff_ab.x * src.xyz * dst.a - + porterduff_ab.y * dst.xyz * src.a - + porterduff_xyz.y * src.xyz * (1.0 - dst.a) - + porterduff_xyz.z * dst.xyz * (1.0 - src.a); - - result.a = dot(porterduff_xyz, vec3(src.a * dst.a, src.a * (1.0 - dst.a), dst.a * (1.0 - src.a))); - - return result; -} diff --git a/src/opengl/util/solid_brush.glsl b/src/opengl/util/solid_brush.glsl deleted file mode 100644 index 760afd1a72..0000000000 --- a/src/opengl/util/solid_brush.glsl +++ /dev/null @@ -1,4 +0,0 @@ -vec4 brush() -{ - return gl_Color; -} diff --git a/src/opengl/util/texture_brush.glsl b/src/opengl/util/texture_brush.glsl deleted file mode 100644 index 949825583f..0000000000 --- a/src/opengl/util/texture_brush.glsl +++ /dev/null @@ -1,21 +0,0 @@ -uniform sampler2D brush_texture; -uniform vec2 inv_brush_texture_size; -uniform vec3 inv_matrix_m0; -uniform vec3 inv_matrix_m1; -uniform vec3 inv_matrix_m2; - -vec4 brush() -{ - mat3 mat; - - mat[0] = inv_matrix_m0; - mat[1] = inv_matrix_m1; - mat[2] = inv_matrix_m2; - - vec3 hcoords = mat * vec3(gl_FragCoord.xy, 1); - vec2 coords = hcoords.xy / hcoords.z; - - coords *= inv_brush_texture_size; - - return texture2D(brush_texture, coords); -} diff --git a/src/opengl/util/trap_exact_aa.glsl b/src/opengl/util/trap_exact_aa.glsl deleted file mode 100644 index 1637f430b5..0000000000 --- a/src/opengl/util/trap_exact_aa.glsl +++ /dev/null @@ -1,58 +0,0 @@ -float quad_aa() -{ - float top = min(gl_FragCoord.y + 0.5, gl_TexCoord[0].x); - float bottom = max(gl_FragCoord.y - 0.5, gl_TexCoord[0].y); - - float area = top - bottom; - - float left = gl_FragCoord.x - 0.5; - float right = gl_FragCoord.x + 0.5; - - // use line equations to compute intersections of left/right edges with top/bottom of truncated pixel - vec4 vecX = gl_TexCoord[1].xxzz * vec2(top, bottom).xyxy + gl_TexCoord[1].yyww; - - vec2 invA = gl_TexCoord[0].zw; - - // transform right line to left to be able to use same calculations for both - vecX.zw = 2.0 * gl_FragCoord.x - vecX.zw; - - vec2 topX = vec2(vecX.x, vecX.z); - vec2 bottomX = vec2(vecX.y, vecX.w); - - // transform lines such that top intersection is to the right of bottom intersection - vec2 topXTemp = max(topX, bottomX); - vec2 bottomXTemp = min(topX, bottomX); - - // make sure line slope reflects mirrored lines - invA = mix(invA, -invA, step(topX, bottomX)); - - vec2 vecLeftRight = vec2(left, right); - - // compute the intersections of the lines with the left and right edges of the pixel - vec4 intersectY = bottom + (vecLeftRight.xyxy - bottomXTemp.xxyy) * invA.xxyy; - - vec2 temp = mix(area - 0.5 * (right - bottomXTemp) * (intersectY.yw - bottom), // left < bottom < right < top - (0.5 * (topXTemp + bottomXTemp) - left) * area, // left < bottom < top < right - step(topXTemp, right.xx)); - - vec2 excluded = 0.5 * (top - intersectY.xz) * (topXTemp - left); // bottom < left < top < right - - excluded = mix((top - 0.5 * (intersectY.yw + intersectY.xz)) * (right - left), // bottom < left < right < top - excluded, step(topXTemp, right.xx)); - - excluded = mix(temp, // left < bottom < right (see calculation of temp) - excluded, step(bottomXTemp, left.xx)); - - excluded = mix(vec2(area, area), // right < bottom < top - excluded, step(bottomXTemp, right.xx)); - - excluded *= step(left, topXTemp); - - return (area - excluded.x - excluded.y) * step(bottom, top); -} - -void main() -{ - gl_FragColor = quad_aa().xxxx; -} - diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 0e61dd3486..58debb8ba8 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -47,7 +47,7 @@ #include -QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformGLContext *share, EGLDisplay display, +QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLint eglClientVersion, EGLenum eglApi) : m_eglDisplay(display) , m_eglApi(eglApi) diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h index 56a873afcb..2fe0e04388 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext_p.h +++ b/src/platformsupport/eglconvenience/qeglplatformcontext_p.h @@ -43,13 +43,13 @@ #define QEGLPLATFORMCONTEXT_H #include -#include +#include #include -class QEGLPlatformContext : public QPlatformGLContext +class QEGLPlatformContext : public QPlatformOpenGLContext { public: - QEGLPlatformContext(const QSurfaceFormat &format, QPlatformGLContext *share, EGLDisplay display, + QEGLPlatformContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLint eglClientVersion = 2, EGLenum eglApi = EGL_OPENGL_ES_API); ~QEGLPlatformContext(); diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 786db322c1..1b84e7b305 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -2,8 +2,8 @@ #define QCOCOAGLCONTEXT_H #include -#include -#include +#include +#include #include #undef slots @@ -11,10 +11,10 @@ QT_BEGIN_NAMESPACE -class QCocoaGLContext : public QPlatformGLContext +class QCocoaGLContext : public QPlatformOpenGLContext { public: - QCocoaGLContext(const QSurfaceFormat &format, QPlatformGLContext *share); + QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share); QSurfaceFormat format() const; diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index c743fcb514..fabed4e207 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -7,7 +7,7 @@ #import -QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformGLContext *share) +QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share) : m_format(format) { QCocoaAutoReleasePool pool; // For the SG Canvas render thread. diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 075405a9d6..0c1b350cef 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -77,7 +77,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; - QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const; QAbstractEventDispatcher *guiThreadEventDispatcher() const; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 1ea4561315..af6cad2da0 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -115,7 +115,7 @@ QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWindow *window) const return new QCocoaWindow(window); } -QPlatformGLContext *QCocoaIntegration::createPlatformGLContext(QGuiGLContext *context) const +QPlatformOpenGLContext *QCocoaIntegration::createPlatformGLContext(QOpenGLContext *context) const { return new QCocoaGLContext(context->format(), context->shareHandle()); } diff --git a/src/plugins/platforms/directfb/qdirectfbglcontext.cpp b/src/plugins/platforms/directfb/qdirectfbglcontext.cpp index 8a40b2476d..c187ec7f66 100644 --- a/src/plugins/platforms/directfb/qdirectfbglcontext.cpp +++ b/src/plugins/platforms/directfb/qdirectfbglcontext.cpp @@ -70,13 +70,13 @@ QDirectFbGLContext::QDirectFbGLContext(IDirectFBGL *glContext) void QDirectFbGLContext::makeCurrent() { - QPlatformGLContext::makeCurrent(); + QPlatformOpenGLContext::makeCurrent(); m_dfbGlContext->Lock(m_dfbGlContext); } void QDirectFbGLContext::doneCurrent() { - QPlatformGLContext::doneCurrent(); + QPlatformOpenGLContext::doneCurrent(); m_dfbGlContext->Unlock(m_dfbGlContext); } diff --git a/src/plugins/platforms/directfb/qdirectfbglcontext.h b/src/plugins/platforms/directfb/qdirectfbglcontext.h index bff8b28d08..97bab0dcb0 100644 --- a/src/plugins/platforms/directfb/qdirectfbglcontext.h +++ b/src/plugins/platforms/directfb/qdirectfbglcontext.h @@ -42,11 +42,11 @@ #ifndef QDIRECTFBGLCONTEXT_H #define QDIRECTFBGLCONTEXT_H -#include +#include #include "qdirectfbconvenience.h" -class QDirectFbGLContext : public QPlatformGLContext +class QDirectFbGLContext : public QPlatformOpenGLContext { public: explicit QDirectFbGLContext(IDirectFBGL *glContext); diff --git a/src/plugins/platforms/directfb/qdirectfbwindow.cpp b/src/plugins/platforms/directfb/qdirectfbwindow.cpp index 40b2cec4ff..e75291b5c1 100644 --- a/src/plugins/platforms/directfb/qdirectfbwindow.cpp +++ b/src/plugins/platforms/directfb/qdirectfbwindow.cpp @@ -169,4 +169,3 @@ WId QDirectFbWindow::winId() const m_dfbWindow->GetID(m_dfbWindow, &id); return WId(id); } - diff --git a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp index c3090428de..1d27be7fb3 100644 --- a/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp +++ b/src/plugins/platforms/eglfs/qeglfsbackingstore.cpp @@ -43,7 +43,7 @@ #include "qeglfsbackingstore.h" -#include +#include #include #include @@ -62,7 +62,7 @@ public: } QSize size() const { return m_screen->geometry().size(); } - QGLContext* context() const { return QGLContext::fromGuiGLContext(m_screen->platformContext()->context()); } + QGLContext* context() const { return QGLContext::fromOpenGLContext(m_screen->platformContext()->context()); } QPaintEngine *paintEngine() const { return qt_qgl_paint_engine(); } diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index 8b2346b5fd..3d3e05d351 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -49,7 +49,7 @@ #include #include -#include +#include #include #include @@ -93,7 +93,7 @@ QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *wi return new QEglFSBackingStore(window); } -QPlatformGLContext *QEglFSIntegration::createPlatformGLContext(QGuiGLContext *context) const +QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { return static_cast(context->screen()->handle())->platformContext(); } diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index 66fda9c673..9538850faf 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -60,7 +60,7 @@ public: QPlatformWindow *createPlatformWindow(QWindow *window) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; - QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; QPlatformFontDatabase *fontDatabase() const; diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp index 953ae704dc..6f317a375f 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp @@ -90,7 +90,7 @@ static struct AttrInfo attrs[] = { class QEglFSContext : public QEGLPlatformContext { public: - QEglFSContext(const QSurfaceFormat &format, QPlatformGLContext *share, EGLDisplay display, + QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLint eglClientVersion = 2, EGLenum eglApi = EGL_OPENGL_ES_API) : QEGLPlatformContext(format, share, display, eglClientVersion, eglApi) { @@ -238,7 +238,7 @@ QImage::Format QEglFSScreen::format() const createAndSetPlatformContext(); return m_format; } -QPlatformGLContext *QEglFSScreen::platformContext() const +QPlatformOpenGLContext *QEglFSScreen::platformContext() const { if (!m_platformContext) { QEglFSScreen *that = const_cast(this); diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h index 230acf3a4b..41465d871c 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.h +++ b/src/plugins/platforms/eglfs/qeglfsscreen.h @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE -class QPlatformGLContext; +class QPlatformOpenGLContext; class QEglFSScreen : public QPlatformScreen //huh: FullScreenScreen ;) just to follow namespace { @@ -62,7 +62,7 @@ public: int depth() const; QImage::Format format() const; - QPlatformGLContext *platformContext() const; + QPlatformOpenGLContext *platformContext() const; EGLSurface surface() const { return m_surface; } @@ -73,7 +73,7 @@ private: QRect m_geometry; int m_depth; QImage::Format m_format; - QPlatformGLContext *m_platformContext; + QPlatformOpenGLContext *m_platformContext; EGLDisplay m_dpy; EGLSurface m_surface; }; diff --git a/src/plugins/platforms/kms/qkmscontext.cpp b/src/plugins/platforms/kms/qkmscontext.cpp index 835b6e8e7a..f27673a24d 100644 --- a/src/plugins/platforms/kms/qkmscontext.cpp +++ b/src/plugins/platforms/kms/qkmscontext.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QKmsContext::QKmsContext(QKmsDevice *device) - : QPlatformGLContext(), + : QPlatformOpenGLContext(), m_device(device) { } @@ -72,7 +72,7 @@ bool QKmsContext::makeCurrent(QPlatformSurface *surface) void QKmsContext::doneCurrent() { - QPlatformGLContext::doneCurrent(); + QPlatformOpenGLContext::doneCurrent(); bool ok = eglMakeCurrent(m_device->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (!ok) diff --git a/src/plugins/platforms/kms/qkmscontext.h b/src/plugins/platforms/kms/qkmscontext.h index 25398c5530..2f4f44c3d0 100644 --- a/src/plugins/platforms/kms/qkmscontext.h +++ b/src/plugins/platforms/kms/qkmscontext.h @@ -42,7 +42,7 @@ #ifndef QKMSCONTEXT_H #define QKMSCONTEXT_H -#include +#include #define EGL_EGLEXT_PROTOTYPES 1 #include @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE class QKmsDevice; -class QKmsContext : public QPlatformGLContext +class QKmsContext : public QPlatformOpenGLContext { public: QKmsContext(QKmsDevice *device); diff --git a/src/plugins/platforms/kms/qkmsintegration.cpp b/src/plugins/platforms/kms/qkmsintegration.cpp index e67f0ec245..d8e4876eee 100644 --- a/src/plugins/platforms/kms/qkmsintegration.cpp +++ b/src/plugins/platforms/kms/qkmsintegration.cpp @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include QT_BEGIN_NAMESPACE @@ -91,7 +91,7 @@ bool QKmsIntegration::hasCapability(QPlatformIntegration::Capability cap) const } } -QPlatformGLContext *QKmsIntegration::createPlatformGLContext(QGuiGLContext *context) const +QPlatformOpenGLContext *QKmsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { QKmsScreen *screen = static_cast(context->screen()->handle()); return new QKmsContext(screen->device()); diff --git a/src/plugins/platforms/kms/qkmsintegration.h b/src/plugins/platforms/kms/qkmsintegration.h index bf84e1b33b..a1f3623280 100644 --- a/src/plugins/platforms/kms/qkmsintegration.h +++ b/src/plugins/platforms/kms/qkmsintegration.h @@ -57,7 +57,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; - QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; diff --git a/src/plugins/platforms/openkode/qopenkodeintegration.h b/src/plugins/platforms/openkode/qopenkodeintegration.h index fb68e123cc..43961add6d 100644 --- a/src/plugins/platforms/openkode/qopenkodeintegration.h +++ b/src/plugins/platforms/openkode/qopenkodeintegration.h @@ -48,7 +48,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/platforms/openkode/qopenkodewindow.cpp b/src/plugins/platforms/openkode/qopenkodewindow.cpp index 2215cd0a92..e20904470f 100644 --- a/src/plugins/platforms/openkode/qopenkodewindow.cpp +++ b/src/plugins/platforms/openkode/qopenkodewindow.cpp @@ -235,7 +235,7 @@ WId QOpenKODEWindow::winId() const return i++; } -QPlatformGLContext *QOpenKODEWindow::glContext() const +QPlatformOpenGLContext *QOpenKODEWindow::glContext() const { return m_platformGlContext; } diff --git a/src/plugins/platforms/openkode/qopenkodewindow.h b/src/plugins/platforms/openkode/qopenkodewindow.h index 317a6b5cd6..f48c3a2bc0 100644 --- a/src/plugins/platforms/openkode/qopenkodewindow.h +++ b/src/plugins/platforms/openkode/qopenkodewindow.h @@ -63,7 +63,7 @@ public: void setVisible(bool visible); WId winId() const; - QPlatformGLContext *glContext() const; + QPlatformOpenGLContext *glContext() const; void raise(); void lower(); diff --git a/src/plugins/platforms/openwfd/qopenwfdglcontext.cpp b/src/plugins/platforms/openwfd/qopenwfdglcontext.cpp index 87d7af4a02..0db717c4d6 100644 --- a/src/plugins/platforms/openwfd/qopenwfdglcontext.cpp +++ b/src/plugins/platforms/openwfd/qopenwfdglcontext.cpp @@ -45,7 +45,7 @@ #include "qopenwfdscreen.h" QOpenWFDGLContext::QOpenWFDGLContext(QOpenWFDDevice *device) - : QPlatformGLContext() + : QPlatformOpenGLContext() , mWfdDevice(device) { } diff --git a/src/plugins/platforms/openwfd/qopenwfdglcontext.h b/src/plugins/platforms/openwfd/qopenwfdglcontext.h index 0f53b9653b..3287a853c7 100644 --- a/src/plugins/platforms/openwfd/qopenwfdglcontext.h +++ b/src/plugins/platforms/openwfd/qopenwfdglcontext.h @@ -42,11 +42,11 @@ #ifndef QOPENWFDGLCONTEXT_H #define QOPENWFDGLCONTEXT_H -#include +#include #include "qopenwfddevice.h" -class QOpenWFDGLContext : public QPlatformGLContext +class QOpenWFDGLContext : public QPlatformOpenGLContext { public: QOpenWFDGLContext(QOpenWFDDevice *device); diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp index 63d7b6a31f..3d57759183 100644 --- a/src/plugins/platforms/openwfd/qopenwfdintegration.cpp +++ b/src/plugins/platforms/openwfd/qopenwfdintegration.cpp @@ -50,7 +50,7 @@ #include #include -#include +#include #include #include @@ -107,7 +107,7 @@ QPlatformWindow *QOpenWFDIntegration::createPlatformWindow(QWindow *window) cons return new QOpenWFDWindow(window); } -QPlatformGLContext *QOpenWFDIntegration::createPlatformGLContext(QGuiGLContext *context) const +QPlatformOpenGLContext *QOpenWFDIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { QOpenWFDScreen *screen = static_cast(context->screen()->handle()); diff --git a/src/plugins/platforms/openwfd/qopenwfdintegration.h b/src/plugins/platforms/openwfd/qopenwfdintegration.h index 18d87fd90e..b5315b31da 100644 --- a/src/plugins/platforms/openwfd/qopenwfdintegration.h +++ b/src/plugins/platforms/openwfd/qopenwfdintegration.h @@ -59,7 +59,7 @@ public: bool hasCapability(Capability cap) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; - QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; //This should not be a factory interface, but rather a accessor QAbstractEventDispatcher *guiThreadEventDispatcher() const; diff --git a/src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp b/src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp index e46c0fbfa1..758e0c4398 100644 --- a/src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp +++ b/src/plugins/platforms/openwfd/qopenwfdnativeinterface.cpp @@ -68,7 +68,7 @@ public: Q_GLOBAL_STATIC(QOpenWFDResourceMap, qOpenWFDResourceMap) -void *QOpenWFDNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QGuiGLContext *context) +void *QOpenWFDNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) { QByteArray lowerCaseResource = resourceString.toLower(); ResourceType resource = qOpenWFDResourceMap()->value(lowerCaseResource); @@ -134,7 +134,7 @@ void *QOpenWFDNativeInterface::eglDisplayForWindow(QWindow *window) return openWFDwindow->port()->device()->eglDisplay(); } -void * QOpenWFDNativeInterface::eglContextForContext(QGuiGLContext *context) +void * QOpenWFDNativeInterface::eglContextForContext(QOpenGLContext *context) { QOpenWFDGLContext *openWFDContext = static_cast(context->handle()); return openWFDContext->eglContext(); diff --git a/src/plugins/platforms/openwfd/qopenwfdnativeinterface.h b/src/plugins/platforms/openwfd/qopenwfdnativeinterface.h index 8123bdfda1..cff49dc8b0 100644 --- a/src/plugins/platforms/openwfd/qopenwfdnativeinterface.h +++ b/src/plugins/platforms/openwfd/qopenwfdnativeinterface.h @@ -59,7 +59,7 @@ public: WFDPipeline }; - void *nativeResourceForContext(const QByteArray &resourceString, QGuiGLContext *context); + void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); WFDHandle wfdDeviceForWindow(QWindow *window); @@ -67,7 +67,7 @@ public: WFDHandle wfdPortForWindow(QWindow *window); WFDHandle wfdPipelineForWindow(QWindow *window); - void *eglContextForContext(QGuiGLContext *context); + void *eglContextForContext(QOpenGLContext *context); private: static QOpenWFDScreen *qPlatformScreenForWindow(QWindow *window); diff --git a/src/plugins/platforms/uikit/quikitwindow.h b/src/plugins/platforms/uikit/quikitwindow.h index c482dae3d5..67f0242a48 100644 --- a/src/plugins/platforms/uikit/quikitwindow.h +++ b/src/plugins/platforms/uikit/quikitwindow.h @@ -117,7 +117,7 @@ public: UIWindow *ensureNativeWindow(); - QPlatformGLContext *glContext() const; + QPlatformOpenGLContext *glContext() const; private: QUIKitScreen *mScreen; diff --git a/src/plugins/platforms/uikit/quikitwindow.mm b/src/plugins/platforms/uikit/quikitwindow.mm index 29ca88b75a..cc17dbcbfb 100644 --- a/src/plugins/platforms/uikit/quikitwindow.mm +++ b/src/plugins/platforms/uikit/quikitwindow.mm @@ -48,12 +48,12 @@ #include #include #include -#include +#include #include #include -class EAGLPlatformContext : public QPlatformGLContext +class EAGLPlatformContext : public QPlatformOpenGLContext { public: EAGLPlatformContext(EAGLView *view) @@ -91,13 +91,13 @@ public: void makeCurrent() { - QPlatformGLContext::makeCurrent(); + QPlatformOpenGLContext::makeCurrent(); [mView makeCurrent]; } void doneCurrent() { - QPlatformGLContext::doneCurrent(); + QPlatformOpenGLContext::doneCurrent(); } void swapBuffers() @@ -381,7 +381,7 @@ UIWindow *QUIKitWindow::ensureNativeWindow() return mWindow; } -QPlatformGLContext *QUIKitWindow::glContext() const +QPlatformOpenGLContext *QUIKitWindow::glContext() const { if (!mContext) { mContext = new EAGLPlatformContext(mView); diff --git a/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h b/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h index 2b4f9fe028..4f688e41d8 100644 --- a/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h @@ -46,7 +46,7 @@ class QWaylandWindow; class QWaylandDisplay; class QWindow; -class QPlatformGLContext; +class QPlatformOpenGLContext; class QSurfaceFormat; class QWaylandGLIntegration @@ -58,7 +58,7 @@ public: virtual void initialize() = 0; virtual QWaylandWindow *createEglWindow(QWindow *window) = 0; - virtual QPlatformGLContext *createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const = 0; + virtual QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const = 0; static QWaylandGLIntegration *createGLIntegration(QWaylandDisplay *waylandDisplay); }; diff --git a/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.cpp index d0712a3989..5f7663ef55 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.cpp @@ -44,7 +44,7 @@ #include "qwaylandshmbackingstore.h" #include "qwaylandreadbackcglwindow.h" -#include +#include #include #include @@ -53,8 +53,8 @@ #include -QWaylandReadbackCGLContext::QWaylandReadbackCGLContext(QPlatformGLContext *share) - : QPlatformGLContext() +QWaylandReadbackCGLContext::QWaylandReadbackCGLContext(QPlatformOpenGLContext *share) + : QPlatformOpenGLContext() { Q_UNUSED(share); m_glContext = qcgl_createGlContext(); @@ -82,7 +82,7 @@ void QWaylandReadbackCGLContext::swapBuffers(QPlatformSurface *surface) { Q_UNUSED(surface); - if (QGuiGLContext::currentContext()->handle() != this) { + if (QOpenGLContext::currentContext()->handle() != this) { makeCurrent(surface); } CGLFlushDrawable(m_glContext); diff --git a/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.h b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.h index 7f727ae8f9..eb065c3f69 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglcontext.h @@ -42,7 +42,7 @@ #ifndef QWAYLANDREADBACKCGLCONTEXT_H #define QWAYLANDREADBACKCGLCONTEXT_H -#include +#include #include "qwaylandreadbackcglintegration.h" @@ -51,10 +51,10 @@ class QWaylandReadbackCGLWindow; class QWaylandShmBuffer; -class QWaylandReadbackCGLContext : public QPlatformGLContext +class QWaylandReadbackCGLContext : public QPlatformOpenGLContext { public: - QWaylandReadbackCGLContext(QPlatformGLContext *share); + QWaylandReadbackCGLContext(QPlatformOpenGLContext *share); QSurfaceFormat format() const; diff --git a/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.cpp index c9cc7b4fa1..2878f9e292 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.cpp @@ -71,7 +71,7 @@ QWaylandWindow * QWaylandReadbackCGLIntegration::createEglWindow(QWindow *window return new QWaylandReadbackCGLWindow(window,this); } -QPlatformGLContext *QWaylandReadbackCGLIntegration::createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const +QPlatformOpenGLContext *QWaylandReadbackCGLIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const { return new QWaylandReadbackCGLContext(share); } diff --git a/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.h b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.h index 63b95f5efa..34c8d00a7c 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_cgl/qwaylandreadbackcglintegration.h @@ -61,7 +61,7 @@ public: void initialize(); QWaylandWindow *createEglWindow(QWindow *window); - QPlatformGLContext *createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; QWaylandDisplay *waylandDisplay() const; private: diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp index cd6ab188f7..c03e8a9444 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp @@ -106,7 +106,7 @@ void QWaylandReadbackEglContext::makeCurrent() void QWaylandReadbackEglContext::doneCurrent() { - QPlatformGLContext::doneCurrent(); + QPlatformOpenGLContext::doneCurrent(); eglMakeCurrent(mEglIntegration->eglDisplay(),EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT); } diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h index f57ac46667..75755fbd1a 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h @@ -42,14 +42,14 @@ #ifndef QWAYLANDREADBACKEGLGLCONTEXT_H #define QWAYLANDREADBACKEGLGLCONTEXT_H -#include +#include #include "qwaylandreadbackeglintegration.h" #include "qwaylandreadbackeglwindow.h" class QWaylandShmBuffer; -class QWaylandReadbackEglContext : public QPlatformGLContext +class QWaylandReadbackEglContext : public QPlatformOpenGLContext { public: QWaylandReadbackEglContext(QWaylandReadbackEglIntegration *eglIntegration, QWaylandReadbackEglWindow *window); diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp index 773087f513..39fa3d589c 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp @@ -86,7 +86,7 @@ QWaylandWindow * QWaylandReadbackEglIntegration::createEglWindow(QWindow *window return new QWaylandReadbackEglWindow(window, this); } -QPlatformGLContext *QWaylandReadbackEglWindow::createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const +QPlatformOpenGLContext *QWaylandReadbackEglWindow::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const { return new QWaylandReadbackEglContext(glFormat, share, this); } diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h index d96e6cface..0d6aa55e4e 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h @@ -63,7 +63,7 @@ public: void initialize(); QWaylandWindow *createEglWindow(QWindow *window); - QPlatformGLContext *createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; QWaylandDisplay *waylandDisplay() const; Display *xDisplay() const; diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp index 39ccafec5c..f4bc6379d6 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp @@ -57,7 +57,7 @@ QWaylandWindow::WindowType QWaylandReadbackEglWindow::windowType() const return QWaylandWindow::Egl; } -QPlatformGLContext *QWaylandReadbackEglWindow::glContext() const +QPlatformOpenGLContext *QWaylandReadbackEglWindow::glContext() const { if (!mContext) { QWaylandReadbackEglWindow *that = const_cast(this); diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h index 63ab7a55ae..0852a8ee66 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h @@ -54,7 +54,7 @@ public: WindowType windowType() const; - QPlatformGLContext *glContext() const; + QPlatformOpenGLContext *glContext() const; void setGeometry(const QRect &rect); diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp index dec2cdd428..850e7bb0ac 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp @@ -44,7 +44,7 @@ #include "qwaylandshmbackingstore.h" #include "qwaylandreadbackglxwindow.h" -#include +#include #include static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) @@ -70,7 +70,7 @@ static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) } QWaylandReadbackGlxContext::QWaylandReadbackGlxContext(const QSurfaceFormat &format, - QPlatformGLContext *share, Display *display, int screen) + QPlatformOpenGLContext *share, Display *display, int screen) : m_display(display) { GLXFBConfig config = qglx_findConfig(display, screen, format, GLX_PIXMAP_BIT); @@ -101,8 +101,8 @@ void QWaylandReadbackGlxContext::doneCurrent() void QWaylandReadbackGlxContext::swapBuffers(QPlatformSurface *surface) { - // #### makeCurrent() directly on the platform context doesn't update QGuiGLContext::currentContext() - if (QGuiGLContext::currentContext()->handle() != this) + // #### makeCurrent() directly on the platform context doesn't update QOpenGLContext::currentContext() + if (QOpenGLContext::currentContext()->handle() != this) makeCurrent(surface); QWaylandReadbackGlxWindow *w = static_cast(surface); diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h index d3a028f51a..7b5eeece93 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h @@ -42,7 +42,7 @@ #ifndef QWAYLANDREADBACKGLXCONTEXT_H #define QWAYLANDREADBACKGLXCONTEXT_H -#include +#include #include #include "qwaylandreadbackglxintegration.h" @@ -52,10 +52,10 @@ class QWaylandReadbackGlxWindow; class QWaylandShmBuffer; -class QWaylandReadbackGlxContext : public QPlatformGLContext +class QWaylandReadbackGlxContext : public QPlatformOpenGLContext { public: - QWaylandReadbackGlxContext(const QSurfaceFormat &format, QPlatformGLContext *share, Display *display, int screen); + QWaylandReadbackGlxContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, Display *display, int screen); QSurfaceFormat format() const; diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp index 22ff5dc0c6..752bb06a43 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp @@ -71,7 +71,7 @@ QWaylandWindow * QWaylandReadbackGlxIntegration::createEglWindow(QWindow *window return new QWaylandReadbackGlxWindow(window,this); } -QPlatformGLContext *QWaylandReadbackGlxIntegration::createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const +QPlatformOpenGLContext *QWaylandReadbackGlxIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const { return new QWaylandReadbackGlxContext(glFormat, share, mDisplay, mScreen); } diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h index 05c224263b..ee50d74ebd 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h @@ -61,7 +61,7 @@ public: void initialize(); QWaylandWindow *createEglWindow(QWindow *window); - QPlatformGLContext *createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; QWaylandDisplay *waylandDisplay() const; diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp index 6e72a45bcd..27f17a6153 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp @@ -84,7 +84,7 @@ QWaylandWindow *QWaylandEglIntegration::createEglWindow(QWindow *window) return new QWaylandEglWindow(window); } -QPlatformGLContext *QWaylandEglIntegration::createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const +QPlatformOpenGLContext *QWaylandEglIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const { return new QWaylandGLContext(m_eglDisplay, glFormat, share); } diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h index 5e39e39fe8..7a26c57658 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h @@ -58,7 +58,7 @@ public: void initialize(); QWaylandWindow *createEglWindow(QWindow *window); - QPlatformGLContext *createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; EGLDisplay eglDisplay() const; diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp index d3ece7c7a9..aa61405eb6 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp @@ -47,12 +47,12 @@ #include -#include +#include #include #include -QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, const QSurfaceFormat &format, QPlatformGLContext *share) - : QPlatformGLContext() +QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, const QSurfaceFormat &format, QPlatformOpenGLContext *share) + : QPlatformOpenGLContext() , m_eglDisplay(eglDisplay) , m_config(q_configFromGLFormat(m_eglDisplay, format, true)) , m_format(q_glFormatFromConfig(m_eglDisplay, m_config)) diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h index 592f3d18f5..16d9fa4ada 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h @@ -44,16 +44,16 @@ #include "qwaylanddisplay.h" -#include +#include #include "qwaylandeglinclude.h" class QWaylandWindow; class QWaylandGLWindowSurface; -class QWaylandGLContext : public QPlatformGLContext { +class QWaylandGLContext : public QPlatformOpenGLContext { public: - QWaylandGLContext(EGLDisplay eglDisplay, const QSurfaceFormat &format, QPlatformGLContext *share); + QWaylandGLContext(EGLDisplay eglDisplay, const QSurfaceFormat &format, QPlatformOpenGLContext *share); ~QWaylandGLContext(); void swapBuffers(QPlatformSurface *surface); diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp index 6c1018d79a..f2f9d1ceb6 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp @@ -48,7 +48,7 @@ #include -QWaylandXCompositeEGLContext::QWaylandXCompositeEGLContext(const QSurfaceFormat &format, QPlatformGLContext *share, EGLDisplay display) +QWaylandXCompositeEGLContext::QWaylandXCompositeEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display) : QEGLPlatformContext(format, share, display) { } diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h index f0e96a19af..8420f2be13 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h @@ -42,7 +42,7 @@ #ifndef QWAYLANDXCOMPOSITEEGLCONTEXT_H #define QWAYLANDXCOMPOSITEEGLCONTEXT_H -#include +#include #include "qwaylandxcompositeeglintegration.h" @@ -53,7 +53,7 @@ class QWaylandXCompositeEGLWindow; class QWaylandXCompositeEGLContext : public QEGLPlatformContext { public: - QWaylandXCompositeEGLContext(const QSurfaceFormat &format, QPlatformGLContext *share, EGLDisplay display); + QWaylandXCompositeEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display); void swapBuffers(QPlatformSurface *surface); diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp index 47454dccab..d7e37f8e70 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp @@ -75,7 +75,7 @@ QWaylandWindow * QWaylandXCompositeEGLIntegration::createEglWindow(QWindow *wind return new QWaylandXCompositeEGLWindow(window,this); } -QPlatformGLContext *QWaylandXCompositeEGLIntegration::createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const +QPlatformOpenGLContext *QWaylandXCompositeEGLIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const { return new QWaylandXCompositeEGLContext(glFormat, share, eglDisplay()); } diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h index 1f67bf28e1..74ea930e9a 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h @@ -51,7 +51,7 @@ #include #include -#include +#include #include @@ -69,7 +69,7 @@ public: void initialize(); QWaylandWindow *createEglWindow(QWindow *window); - QPlatformGLContext *createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; QWaylandDisplay *waylandDisplay() const; struct wl_xcomposite *waylandXComposite() const; diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp index 20fb0396f8..75881a7fdd 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp @@ -47,7 +47,7 @@ #include -QWaylandXCompositeGLXContext::QWaylandXCompositeGLXContext(const QSurfaceFormat &format, QPlatformGLContext *share, Display *display, int screen) +QWaylandXCompositeGLXContext::QWaylandXCompositeGLXContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, Display *display, int screen) : m_display(display) { qDebug("creating XComposite-GLX context"); diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h index cabdbe1a82..3364d88ec4 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h @@ -42,7 +42,7 @@ #ifndef QWAYLANDXCOMPOSITEGLXCONTEXT_H #define QWAYLANDXCOMPOSITEGLXCONTEXT_H -#include +#include #include "qwaylandxcompositeglxintegration.h" #include @@ -50,10 +50,10 @@ class QWaylandXCompositeGLXWindow; class QWaylandShmBuffer; -class QWaylandXCompositeGLXContext : public QPlatformGLContext +class QWaylandXCompositeGLXContext : public QPlatformOpenGLContext { public: - QWaylandXCompositeGLXContext(const QSurfaceFormat &format, QPlatformGLContext *share, Display *display, int screen); + QWaylandXCompositeGLXContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, Display *display, int screen); QSurfaceFormat format() const; diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp index 8c27fa1cd8..e1eb2e635a 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp @@ -78,7 +78,7 @@ QWaylandWindow * QWaylandXCompositeGLXIntegration::createEglWindow(QWindow *wind return new QWaylandXCompositeGLXWindow(window, this); } -QPlatformGLContext *QWaylandXCompositeGLXIntegration::createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const +QPlatformOpenGLContext *QWaylandXCompositeGLXIntegration::createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const { return new QWaylandXCompositeGLXContext(glFormat, share, mDisplay, mScreen); } diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h index 5a779bf58a..b028067d8e 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h @@ -64,7 +64,7 @@ public: void initialize(); QWaylandWindow *createEglWindow(QWindow *window); - QPlatformGLContext *createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share) const; QWaylandDisplay *waylandDisplay() const; struct wl_xcomposite *waylandXComposite() const; diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp index 3ed5f163ff..e17c2f8d95 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.cpp +++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp @@ -56,7 +56,7 @@ #include #include #include -#include +#include #ifdef QT_WAYLAND_GL_SUPPORT #include "gl_integration/qwaylandglintegration.h" @@ -104,10 +104,10 @@ QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWindow *window) cons return new QWaylandShmWindow(window); } -QPlatformGLContext *QWaylandIntegration::createPlatformGLContext(QGuiGLContext *context) const +QPlatformOpenGLContext *QWaylandIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { #ifdef QT_WAYLAND_GL_SUPPORT - return mDisplay->eglIntegration()->createPlatformGLContext(context->format(), context->shareHandle()); + return mDisplay->eglIntegration()->createPlatformOpenGLContext(context->format(), context->shareHandle()); #else Q_UNUSED(glFormat); Q_UNUSED(share); diff --git a/src/plugins/platforms/wayland/qwaylandintegration.h b/src/plugins/platforms/wayland/qwaylandintegration.h index 69b8863ebc..61e8559a7d 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.h +++ b/src/plugins/platforms/wayland/qwaylandintegration.h @@ -57,7 +57,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; - QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; QAbstractEventDispatcher *guiThreadEventDispatcher() const; diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index e94b4ffdf2..4abccfb416 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -778,7 +778,7 @@ QDebug operator<<(QDebug d, const QOpenGLStaticContext &s) */ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext, - QGuiGLContext *context) : + QOpenGLContext *context) : m_staticContext(staticContext), m_context(context), m_pixelFormat(0), m_extensionsUsed(false) @@ -843,7 +843,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex } // Create context with sharing, again preferably using ARB. HGLRC sharingRenderingContext = 0; - if (const QPlatformGLContext *sc = context->shareHandle()) + if (const QPlatformOpenGLContext *sc = context->shareHandle()) sharingRenderingContext = static_cast(sc)->renderingContext(); if (m_extensionsUsed) diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index c5edd8978f..0bf8ffbbc5 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -45,8 +45,8 @@ #include "array.h" #include "qtwindows_additional.h" -#include -#include +#include +#include #include QT_BEGIN_NAMESPACE @@ -125,13 +125,13 @@ public: QDebug operator<<(QDebug d, const QOpenGLStaticContext &); -class QWindowsGLContext : public QPlatformGLContext +class QWindowsGLContext : public QPlatformOpenGLContext { public: typedef QSharedPointer QOpenGLStaticContextPtr; explicit QWindowsGLContext(const QOpenGLStaticContextPtr &staticContext, - QGuiGLContext *context); + QOpenGLContext *context); virtual ~QWindowsGLContext(); bool isValid() const { return m_renderingContext; } virtual QSurfaceFormat format() const { return m_obtainedFormat; } @@ -151,7 +151,7 @@ private: inline void releaseDCs(); const QOpenGLStaticContextPtr m_staticContext; - QGuiGLContext *m_context; + QOpenGLContext *m_context; QSurfaceFormat m_obtainedFormat; HGLRC m_renderingContext; Array m_windowContexts; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index fdcc05abe0..cde6da671a 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -217,8 +217,8 @@ QPlatformBackingStore *QWindowsIntegration::createPlatformBackingStore(QWindow * return new QWindowsBackingStore(window); } -QPlatformGLContext - *QWindowsIntegration::createPlatformGLContext(QGuiGLContext *context) const +QPlatformOpenGLContext + *QWindowsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { if (QWindowsContext::verboseIntegration) qDebug() << __FUNCTION__ << context->format(); diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 70f12f8bfd..14a65c67e0 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -60,7 +60,7 @@ public: virtual QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const; QPlatformWindow *createPlatformWindow(QWindow *window) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; - virtual QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const; + virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const; virtual QPlatformClipboard *clipboard() const; diff --git a/src/plugins/platforms/xcb/qdri2context.cpp b/src/plugins/platforms/xcb/qdri2context.cpp index 8eef1b6111..5f4aff5455 100644 --- a/src/plugins/platforms/xcb/qdri2context.cpp +++ b/src/plugins/platforms/xcb/qdri2context.cpp @@ -134,9 +134,9 @@ QDri2Context::QDri2Context(QXcbWindow *window) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERER,d->depth); //restore the old current context - const QPlatformGLContext *currentContext = QPlatformGLContext::currentContext(); + const QPlatformOpenGLContext *currentContext = QPlatformOpenGLContext::currentContext(); if (currentContext) - const_cast(currentContext)->makeCurrent(); + const_cast(currentContext)->makeCurrent(); } QDri2Context::~QDri2Context() diff --git a/src/plugins/platforms/xcb/qdri2context.h b/src/plugins/platforms/xcb/qdri2context.h index be7d637643..ec8b251c3f 100644 --- a/src/plugins/platforms/xcb/qdri2context.h +++ b/src/plugins/platforms/xcb/qdri2context.h @@ -42,14 +42,14 @@ #ifndef QDRI2CONTEXT_H #define QDRI2CONTEXT_H -#include +#include class QXcbWindow; class QDri2ContextPrivate; struct xcb_dri2_dri2_buffer_t; -class QDri2Context : public QPlatformGLContext +class QDri2Context : public QPlatformOpenGLContext { Q_DECLARE_PRIVATE(QDri2Context); public: diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index c35350a288..bf58721d38 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -50,7 +50,7 @@ #include #include -#include +#include #include "qglxintegration.h" #include @@ -59,8 +59,8 @@ #include #endif -QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformGLContext *share) - : QPlatformGLContext() +QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share) + : QPlatformOpenGLContext() , m_screen(screen) , m_context(0) { diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h index b431a45741..bbe67b653a 100644 --- a/src/plugins/platforms/xcb/qglxintegration.h +++ b/src/plugins/platforms/xcb/qglxintegration.h @@ -45,17 +45,17 @@ #include "qxcbwindow.h" #include "qxcbscreen.h" -#include +#include #include #include #include -class QGLXContext : public QPlatformGLContext +class QGLXContext : public QPlatformOpenGLContext { public: - QGLXContext(QXcbScreen *xd, const QSurfaceFormat &format, QPlatformGLContext *share); + QGLXContext(QXcbScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share); ~QGLXContext(); bool makeCurrent(QPlatformSurface *surface); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 54394c9193..41650efcdb 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -73,7 +73,7 @@ #include #endif -#include +#include #include QXcbIntegration::QXcbIntegration(const QStringList ¶meters) @@ -125,7 +125,7 @@ QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const class QEGLXcbPlatformContext : public QEGLPlatformContext { public: - QEGLXcbPlatformContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share, EGLDisplay display) + QEGLXcbPlatformContext(const QSurfaceFormat &glFormat, QPlatformOpenGLContext *share, EGLDisplay display) : QEGLPlatformContext(glFormat, share, display) { } @@ -137,7 +137,7 @@ public: }; #endif -QPlatformGLContext *QXcbIntegration::createPlatformGLContext(QGuiGLContext *context) const +QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { QXcbScreen *screen = static_cast(context->screen()->handle()); #if defined(XCB_USE_GLX) diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 9d49a90d0a..cad127c28e 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -57,7 +57,7 @@ public: ~QXcbIntegration(); QPlatformWindow *createPlatformWindow(QWindow *window) const; - QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; bool hasCapability(Capability cap) const; diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 217dae6bc1..3c9cdfd257 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -48,7 +48,7 @@ #include -#include +#include #include #if defined(XCB_USE_EGL) @@ -74,7 +74,7 @@ public: Q_GLOBAL_STATIC(QXcbResourceMap, qXcbResourceMap) -void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QGuiGLContext *context) +void *QXcbNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) { QByteArray lowerCaseResource = resourceString.toLower(); ResourceType resource = qXcbResourceMap()->value(lowerCaseResource); @@ -174,7 +174,7 @@ void *QXcbNativeInterface::graphicsDeviceForWindow(QWindow *window) } -void * QXcbNativeInterface::eglContextForContext(QGuiGLContext *context) +void * QXcbNativeInterface::eglContextForContext(QOpenGLContext *context) { Q_ASSERT(context); #if defined(XCB_USE_EGL) @@ -183,7 +183,7 @@ void * QXcbNativeInterface::eglContextForContext(QGuiGLContext *context) #endif #if 0 Q_ASSERT(window); - QPlatformGLContext *platformContext = window->glContext()->handle(); + QPlatformOpenGLContext *platformContext = window->glContext()->handle(); if (!platformContext) { qDebug() << "QWindow" << window << "does not have a glContext" << "cannot return EGLContext"; diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index e9b1df4511..8dec83267a 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -59,7 +59,7 @@ public: EglContext }; - void *nativeResourceForContext(const QByteArray &resourceString, QGuiGLContext *context); + void *nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context); void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); void *displayForWindow(QWindow *window); @@ -68,7 +68,7 @@ public: void *screenForWindow(QWindow *window); void *graphicsDeviceForWindow(QWindow *window); - void *eglContextForContext(QGuiGLContext *context); + void *eglContextForContext(QOpenGLContext *context); private: static QXcbScreen *qPlatformScreenForWindow(QWindow *window); diff --git a/src/plugins/platforms/xlib/qglxintegration.cpp b/src/plugins/platforms/xlib/qglxintegration.cpp index ee9f75b4b0..f3badd657f 100644 --- a/src/plugins/platforms/xlib/qglxintegration.cpp +++ b/src/plugins/platforms/xlib/qglxintegration.cpp @@ -61,8 +61,8 @@ QT_BEGIN_NAMESPACE -QGLXContext::QGLXContext(QXlibScreen *screen, const QSurfaceFormat &format, QPlatformGLContext *share) - : QPlatformGLContext() +QGLXContext::QGLXContext(QXlibScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share) + : QPlatformOpenGLContext() , m_screen(screen) , m_context(0) { @@ -105,7 +105,7 @@ bool QGLXContext::makeCurrent(QPlatformSurface *surface) void QGLXContext::doneCurrent() { - QPlatformGLContext::doneCurrent(); + QPlatformOpenGLContext::doneCurrent(); glXMakeCurrent(m_screen->display()->nativeDisplay(), 0, 0); } diff --git a/src/plugins/platforms/xlib/qglxintegration.h b/src/plugins/platforms/xlib/qglxintegration.h index 91e16db79e..e3172b718c 100644 --- a/src/plugins/platforms/xlib/qglxintegration.h +++ b/src/plugins/platforms/xlib/qglxintegration.h @@ -44,7 +44,7 @@ #include "qxlibwindow.h" -#include +#include #include #include @@ -54,10 +54,10 @@ QT_BEGIN_NAMESPACE -class QGLXContext : public QPlatformGLContext +class QGLXContext : public QPlatformOpenGLContext { public: - QGLXContext(QXlibScreen *xd, const QSurfaceFormat &format, QPlatformGLContext *share); + QGLXContext(QXlibScreen *xd, const QSurfaceFormat &format, QPlatformOpenGLContext *share); ~QGLXContext(); QSurfaceFormat format() const; diff --git a/src/plugins/platforms/xlib/qxlibintegration.cpp b/src/plugins/platforms/xlib/qxlibintegration.cpp index 5be7420426..c8a6db92b4 100644 --- a/src/plugins/platforms/xlib/qxlibintegration.cpp +++ b/src/plugins/platforms/xlib/qxlibintegration.cpp @@ -83,7 +83,7 @@ QPlatformBackingStore *QXlibIntegration::createPlatformBackingStore(QWindow *win return new QXlibBackingStore(window); } -QPlatformGLContext *QXlibIntegration::createPlatformGLContext(QGuiGLContext *context) const +QPlatformOpenGLContext *QXlibIntegration::createPlatformGLContext(QOpenGLContext *context) const { QXlibScreen *screen = static_cast(context->screen()->handle()); diff --git a/src/plugins/platforms/xlib/qxlibintegration.h b/src/plugins/platforms/xlib/qxlibintegration.h index bb796314d1..9cdb1dad9c 100644 --- a/src/plugins/platforms/xlib/qxlibintegration.h +++ b/src/plugins/platforms/xlib/qxlibintegration.h @@ -64,7 +64,7 @@ public: QPlatformWindow *createPlatformWindow(QWindow *window) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; - QPlatformGLContext *createPlatformGLContext(QGuiGLContext *context) const; + QPlatformOpenGLContext *createPlatformGLContext(QOpenGLContext *context) const; QAbstractEventDispatcher *guiThreadEventDispatcher() const; diff --git a/src/plugins/platforms/xlib/qxlibwindow.h b/src/plugins/platforms/xlib/qxlibwindow.h index 2508a01565..9b64dc5624 100644 --- a/src/plugins/platforms/xlib/qxlibwindow.h +++ b/src/plugins/platforms/xlib/qxlibwindow.h @@ -145,7 +145,7 @@ private: GC createGC(); - QPlatformGLContext *mGLContext; + QPlatformOpenGLContext *mGLContext; QXlibScreen *mScreen; Qt::WindowFlags mWindowFlags; diff --git a/src/tools/uic/qclass_lib_map.h b/src/tools/uic/qclass_lib_map.h index d44d344bc5..ca79cbb670 100644 --- a/src/tools/uic/qclass_lib_map.h +++ b/src/tools/uic/qclass_lib_map.h @@ -823,7 +823,7 @@ QT_CLASS_LIB(QColorGroup, QtWidgets, qpalette.h) QT_CLASS_LIB(QPlatformCursorImage, QtGui, qplatformcursor_qpa.h) QT_CLASS_LIB(QPlatformCursorPrivate, QtGui, qplatformcursor_qpa.h) QT_CLASS_LIB(QPlatformCursor, QtGui, qplatformcursor_qpa.h) -QT_CLASS_LIB(QPlatformGLContext, QtGui, qplatformglcontext_qpa.h) +QT_CLASS_LIB(QPlatformOpenGLContext, QtGui, qplatformopenglcontext_qpa.h) QT_CLASS_LIB(QPlatformIntegration, QtGui, qplatformintegration_qpa.h) QT_CLASS_LIB(QPlatformIntegrationFactoryInterface, QtGui, qplatformintegrationplugin_qpa.h) QT_CLASS_LIB(QPlatformIntegrationPlugin, QtGui, qplatformintegrationplugin_qpa.h) diff --git a/src/widgets/kernel/qwidget_qpa.cpp b/src/widgets/kernel/qwidget_qpa.cpp index 507cb11fff..39f8aa944d 100644 --- a/src/widgets/kernel/qwidget_qpa.cpp +++ b/src/widgets/kernel/qwidget_qpa.cpp @@ -49,7 +49,7 @@ #include "QtWidgets/qdesktopwidget.h" #include "QtGui/qplatformwindow_qpa.h" #include "QtGui/qsurfaceformat.h" -#include "QtGui/qplatformglcontext_qpa.h" +#include "QtGui/qplatformopenglcontext_qpa.h" #include "QtGui/private/qwindow_p.h" #include @@ -813,7 +813,7 @@ void QWidgetPrivate::deleteTLSysExtra() { if (extra && extra->topextra) { //the toplevel might have a context with a "qglcontext associated with it. We need to - //delete the qglcontext before we delete the qplatformglcontext. + //delete the qglcontext before we delete the qplatformopenglcontext. //One unfortunate thing about this is that we potentially create a glContext just to //delete it straight afterwards. if (extra->topextra->window) {