summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp130
-rw-r--r--src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h43
-rw-r--r--src/opengl/gl2paintengineex/qglcustomshaderstage.cpp138
-rw-r--r--src/opengl/gl2paintengineex/qglcustomshaderstage_p.h93
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp603
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h294
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadersource_p.h157
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache.cpp36
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache_p.h30
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp1646
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h158
-rw-r--r--src/opengl/gl2paintengineex/qtriangulatingstroker.cpp549
-rw-r--r--src/opengl/gl2paintengineex/qtriangulatingstroker_p.h156
-rw-r--r--src/opengl/gl2paintengineex/qtriangulator.cpp2981
-rw-r--r--src/opengl/gl2paintengineex/qtriangulator_p.h98
-rw-r--r--src/opengl/opengl.pro51
-rw-r--r--src/opengl/qgl.cpp1510
-rw-r--r--src/opengl/qgl.h92
-rw-r--r--src/opengl/qgl_cl_p.h30
-rw-r--r--src/opengl/qgl_egl.cpp134
-rw-r--r--src/opengl/qgl_egl_p.h30
-rw-r--r--src/opengl/qgl_mac.mm41
-rw-r--r--src/opengl/qgl_p.h340
-rw-r--r--src/opengl/qgl_qws.cpp173
-rw-r--r--src/opengl/qgl_win.cpp46
-rw-r--r--src/opengl/qgl_wince.cpp149
-rw-r--r--src/opengl/qgl_x11.cpp175
-rw-r--r--src/opengl/qgl_x11egl.cpp529
-rw-r--r--src/opengl/qglcolormap.cpp38
-rw-r--r--src/opengl/qglcolormap.h30
-rw-r--r--src/opengl/qglextensions.cpp133
-rw-r--r--src/opengl/qglextensions_p.h213
-rw-r--r--src/opengl/qglframebufferobject.cpp488
-rw-r--r--src/opengl/qglframebufferobject.h64
-rw-r--r--src/opengl/qglframebufferobject_p.h153
-rw-r--r--src/opengl/qglpaintdevice.cpp224
-rw-r--r--src/opengl/qglpaintdevice_p.h112
-rw-r--r--src/opengl/qglpaintdevice_qws.cpp98
-rw-r--r--src/opengl/qglpaintdevice_qws_p.h85
-rw-r--r--src/opengl/qglpixelbuffer.cpp57
-rw-r--r--src/opengl/qglpixelbuffer.h34
-rw-r--r--src/opengl/qglpixelbuffer_egl.cpp115
-rw-r--r--src/opengl/qglpixelbuffer_mac.mm30
-rw-r--r--src/opengl/qglpixelbuffer_p.h45
-rw-r--r--src/opengl/qglpixelbuffer_win.cpp30
-rw-r--r--src/opengl/qglpixelbuffer_x11.cpp63
-rw-r--r--src/opengl/qglpixmapfilter.cpp1068
-rw-r--r--src/opengl/qglpixmapfilter_p.h30
-rw-r--r--src/opengl/qglscreen_qws.cpp30
-rw-r--r--src/opengl/qglscreen_qws.h30
-rw-r--r--src/opengl/qglshaderprogram.cpp1404
-rw-r--r--src/opengl/qglshaderprogram.h107
-rw-r--r--src/opengl/qglwindowsurface_qws.cpp31
-rw-r--r--src/opengl/qglwindowsurface_qws_p.h30
-rw-r--r--src/opengl/qgraphicsshadereffect.cpp314
-rw-r--r--src/opengl/qgraphicsshadereffect_p.h94
-rw-r--r--src/opengl/qgraphicssystem_gl.cpp45
-rw-r--r--src/opengl/qgraphicssystem_gl_p.h30
-rw-r--r--src/opengl/qpaintengine_opengl.cpp304
-rw-r--r--src/opengl/qpaintengine_opengl_p.h36
-rw-r--r--src/opengl/qpixmapdata_gl.cpp421
-rw-r--r--src/opengl/qpixmapdata_gl_p.h95
-rw-r--r--src/opengl/qpixmapdata_x11gl_egl.cpp252
-rw-r--r--src/opengl/qpixmapdata_x11gl_p.h86
-rw-r--r--src/opengl/qwindowsurface_gl.cpp319
-rw-r--r--src/opengl/qwindowsurface_gl_p.h49
-rw-r--r--src/opengl/qwindowsurface_x11gl.cpp147
-rw-r--r--src/opengl/qwindowsurface_x11gl_p.h81
-rw-r--r--src/opengl/util/composition_mode_colorburn.glsl4
-rw-r--r--src/opengl/util/composition_mode_colordodge.glsl4
-rw-r--r--src/opengl/util/composition_mode_darken.glsl2
-rw-r--r--src/opengl/util/composition_mode_difference.glsl2
-rw-r--r--src/opengl/util/composition_mode_exclusion.glsl2
-rw-r--r--src/opengl/util/composition_mode_hardlight.glsl6
-rw-r--r--src/opengl/util/composition_mode_lighten.glsl2
-rw-r--r--src/opengl/util/composition_mode_multiply.glsl2
-rw-r--r--src/opengl/util/composition_mode_overlay.glsl6
-rw-r--r--src/opengl/util/composition_mode_softlight.glsl24
-rw-r--r--src/opengl/util/conical_brush.glsl2
-rw-r--r--src/opengl/util/ellipse.glsl6
-rw-r--r--src/opengl/util/ellipse_aa.glsl56
-rw-r--r--src/opengl/util/ellipse_aa_copy.glsl11
-rw-r--r--src/opengl/util/ellipse_aa_radial.glsl24
-rw-r--r--src/opengl/util/ellipse_functions.glsl63
-rw-r--r--src/opengl/util/fragmentprograms_p.h7357
-rw-r--r--src/opengl/util/generator.cpp142
-rw-r--r--src/opengl/util/generator.pro2
-rwxr-xr-xsrc/opengl/util/glsl_to_include.sh40
-rw-r--r--src/opengl/util/masks.conf1
-rw-r--r--src/opengl/util/pattern_brush.glsl4
-rw-r--r--src/opengl/util/simple_porter_duff.glsl6
-rw-r--r--src/opengl/util/texture_brush.glsl2
-rw-r--r--src/opengl/util/trap_exact_aa.glsl12
93 files changed, 16510 insertions, 8699 deletions
diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
index 8f9a6a965..ee1a797b1 100644
--- a/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
+++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
void QGL2PEXVertexArray::clear()
{
vertexArray.reset();
- vertexArrayStops.clear();
+ vertexArrayStops.reset();
boundingRectDirty = true;
}
@@ -67,7 +67,30 @@ void QGL2PEXVertexArray::addRect(const QRectF &rect)
<< rect.bottomRight() << rect.bottomLeft() << rect.topLeft();
}
-void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale)
+void QGL2PEXVertexArray::addClosingLine(int index)
+{
+ if (QPointF(vertexArray.at(index)) != QPointF(vertexArray.last()))
+ vertexArray.add(vertexArray.at(index));
+}
+
+void QGL2PEXVertexArray::addCentroid(const QVectorPath &path, int subPathIndex)
+{
+ const QPointF *const points = reinterpret_cast<const QPointF *>(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 QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline)
{
const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
const QPainterPath::ElementType* const elements = path.elements();
@@ -78,6 +101,10 @@ void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseSc
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 {
@@ -93,29 +120,47 @@ void QGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseSc
// qDebug("QVectorPath has element types");
for (int i=1; i<path.elementCount(); ++i) {
- const QPainterPath::ElementType elementType = elements[i];
- switch (elementType) {
+ switch (elements[i]) {
case QPainterPath::MoveToElement:
+ if (!outline)
+ addClosingLine(lastMoveTo);
// qDebug("element[%d] is a MoveToElement", i);
- vertexArrayStops.append(vertexArray.size());
- vertexArray.add(points[i]); // Add the moveTo as a new vertex
+ vertexArrayStops.add(vertexArray.size());
+ if (!outline) {
+ if (!path.isConvex()) addCentroid(path, i);
+ lastMoveTo = vertexArray.size();
+ }
+ lineToArray(points[i].x(), points[i].y()); // Add the moveTo as a new vertex
break;
case QPainterPath::LineToElement:
// qDebug("element[%d] is a LineToElement", i);
lineToArray(points[i].x(), points[i].y());
break;
- case QPainterPath::CurveToElement:
-// qDebug("element[%d] is a CurveToElement", i);
- curveToArray(points[i], points[i+1], points[i+2], curveInverseScale);
- i+=2;
- break;
+ case QPainterPath::CurveToElement: {
+ QBezier b = QBezier::fromPoints(*(((const QPointF *) points) + i - 1),
+ points[i],
+ points[i+1],
+ points[i+2]);
+ QRectF bounds = b.bounds();
+ // threshold based on same algorithm as in qtriangulatingstroker.cpp
+ int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * 3.14f / (curveInverseScale * 6));
+ if (threshold < 3) threshold = 3;
+ qreal one_over_threshold_minus_1 = 1.f / (threshold - 1);
+ for (int t=0; t<threshold; ++t) {
+ QPointF pt = b.pointAt(t * one_over_threshold_minus_1);
+ lineToArray(pt.x(), pt.y());
+ }
+ i += 2;
+ break; }
default:
break;
}
}
} while (0);
- vertexArrayStops.append(vertexArray.size());
+ if (!outline)
+ addClosingLine(lastMoveTo);
+ vertexArrayStops.add(vertexArray.size());
}
void QGL2PEXVertexArray::lineToArray(const GLfloat x, const GLfloat y)
@@ -132,35 +177,4 @@ void QGL2PEXVertexArray::lineToArray(const GLfloat x, const GLfloat y)
minY = y;
}
-void QGL2PEXVertexArray::curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale)
-{
- qreal inverseScaleHalf = inverseScale / 2;
-
- QBezier beziers[32];
- beziers[0] = QBezier::fromPoints(vertexArray.last(), cp1, cp2, ep);
- QBezier *b = beziers;
- while (b >= beziers) {
- // check if we can pop the top bezier curve from the stack
- qreal l = qAbs(b->x4 - b->x1) + qAbs(b->y4 - b->y1);
- qreal d;
- if (l > inverseScale) {
- d = qAbs( (b->x4 - b->x1)*(b->y1 - b->y2) - (b->y4 - b->y1)*(b->x1 - b->x2) )
- + qAbs( (b->x4 - b->x1)*(b->y1 - b->y3) - (b->y4 - b->y1)*(b->x1 - b->x3) );
- d /= l;
- } else {
- d = qAbs(b->x1 - b->x2) + qAbs(b->y1 - b->y2) +
- qAbs(b->x1 - b->x3) + qAbs(b->y1 - b->y3);
- }
- if (d < inverseScaleHalf || b == beziers + 31) {
- // good enough, we pop it off and add the endpoint
- lineToArray(b->x4, b->y4);
- --b;
- } else {
- // split, second half of the polygon goes lower into the stack
- b->split(b+1, b);
- ++b;
- }
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
index 0f41ded5b..98eaa91bb 100644
--- a/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
+++ b/src/opengl/gl2paintengineex/qgl2pexvertexarray_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -104,26 +104,29 @@ public:
boundingRectDirty(true) {}
void addRect(const QRectF &rect);
- void addPath(const QVectorPath &path, GLfloat curveInverseScale);
+ void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true);
void clear();
QGLPoint* data() {return vertexArray.data();}
- QVector<int>& stops() {return vertexArrayStops;}
+ int *stops() const { return vertexArrayStops.data(); }
+ int stopCount() const { return vertexArrayStops.size(); }
QGLRect boundingRect() const;
+ int vertexCount() const { return vertexArray.size(); }
+
void lineToArray(const GLfloat x, const GLfloat y);
private:
QDataBuffer<QGLPoint> vertexArray;
- QVector<int> vertexArrayStops;
+ QDataBuffer<int> vertexArrayStops;
GLfloat maxX;
GLfloat maxY;
GLfloat minX;
GLfloat minY;
bool boundingRectDirty;
-
- inline void curveToArray(const QGLPoint &cp1, const QGLPoint &cp2, const QGLPoint &ep, GLfloat inverseScale);
+ void addClosingLine(int index);
+ void addCentroid(const QVectorPath &path, int subPathIndex);
};
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
new file mode 100644
index 000000000..b71a7b743
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglcustomshaderstage_p.h"
+#include "qglengineshadermanager_p.h"
+#include "qpaintengineex_opengl2_p.h"
+#include <private/qpainter_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLCustomShaderStagePrivate
+{
+public:
+ QGLCustomShaderStagePrivate() :
+ m_manager(0) {}
+
+ QPointer<QGLEngineShaderManager> m_manager;
+ QByteArray m_source;
+};
+
+
+
+
+QGLCustomShaderStage::QGLCustomShaderStage()
+ : d_ptr(new QGLCustomShaderStagePrivate)
+{
+}
+
+QGLCustomShaderStage::~QGLCustomShaderStage()
+{
+ Q_D(QGLCustomShaderStage);
+ if (d->m_manager) {
+ d->m_manager->removeCustomStage();
+ d->m_manager->sharedShaders->cleanupCustomStage(this);
+ }
+}
+
+void QGLCustomShaderStage::setUniformsDirty()
+{
+ Q_D(QGLCustomShaderStage);
+ if (d->m_manager)
+ d->m_manager->setDirty(); // ### Probably a bit overkill!
+}
+
+bool QGLCustomShaderStage::setOnPainter(QPainter* p)
+{
+ Q_D(QGLCustomShaderStage);
+ if (p->paintEngine()->type() != QPaintEngine::OpenGL2) {
+ qWarning("QGLCustomShaderStage::setOnPainter() - paint engine not OpenGL2");
+ return false;
+ }
+ if (d->m_manager)
+ qWarning("Custom shader is already set on a painter");
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx*>(p->paintEngine());
+ d->m_manager = QGL2PaintEngineExPrivate::shaderManagerForEngine(engine);
+ Q_ASSERT(d->m_manager);
+
+ d->m_manager->setCustomStage(this);
+ return true;
+}
+
+void QGLCustomShaderStage::removeFromPainter(QPainter* p)
+{
+ Q_D(QGLCustomShaderStage);
+ if (p->paintEngine()->type() != QPaintEngine::OpenGL2)
+ return;
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx*>(p->paintEngine());
+ d->m_manager = QGL2PaintEngineExPrivate::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 QGLCustomShaderStage::source() const
+{
+ Q_D(const QGLCustomShaderStage);
+ return d->m_source;
+}
+
+// Called by the shader manager if another custom shader is attached or
+// the manager is deleted
+void QGLCustomShaderStage::setInactive()
+{
+ Q_D(QGLCustomShaderStage);
+ d->m_manager = 0;
+}
+
+void QGLCustomShaderStage::setSource(const QByteArray& s)
+{
+ Q_D(QGLCustomShaderStage);
+ d->m_source = s;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h
new file mode 100644
index 000000000..e3193894b
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGL_CUSTOM_SHADER_STAGE_H
+#define QGL_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 <QGLShaderProgram>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(OpenGL)
+
+class QGLCustomShaderStagePrivate;
+class Q_OPENGL_EXPORT QGLCustomShaderStage
+{
+ Q_DECLARE_PRIVATE(QGLCustomShaderStage)
+public:
+ QGLCustomShaderStage();
+ virtual ~QGLCustomShaderStage();
+ virtual void setUniforms(QGLShaderProgram*) = 0;
+
+ void setUniformsDirty();
+
+ bool setOnPainter(QPainter*);
+ void removeFromPainter(QPainter*);
+ QByteArray source() const;
+
+ void setInactive();
+protected:
+ void setSource(const QByteArray&);
+
+private:
+ QGLCustomShaderStagePrivate* d_ptr;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+
+#endif
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index 42b36a2ee..8a8f4835e 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -49,48 +49,35 @@
QT_BEGIN_NAMESPACE
-static void QGLEngineShaderManager_free(void *ptr)
+static void qt_shared_shaders_free(void *data)
{
- delete reinterpret_cast<QGLEngineShaderManager *>(ptr);
+ delete reinterpret_cast<QGLEngineSharedShaders *>(data);
}
-Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shader_managers, (QGLEngineShaderManager_free))
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_shaders, (qt_shared_shaders_free))
-QGLEngineShaderManager *QGLEngineShaderManager::managerForContext(const QGLContext *context)
+QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLContext *context)
{
- QGLEngineShaderManager *p = reinterpret_cast<QGLEngineShaderManager *>(qt_shader_managers()->value(context));
+ QGLEngineSharedShaders *p = reinterpret_cast<QGLEngineSharedShaders *>(qt_shared_shaders()->value(context));
if (!p) {
- QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
- if (oldContext != context)
- const_cast<QGLContext *>(context)->makeCurrent();
- p = new QGLEngineShaderManager(const_cast<QGLContext *>(context));
- qt_shader_managers()->insert(context, p);
- if (oldContext && oldContext != context)
- oldContext->makeCurrent();
+ QGLShareContextScope scope(context);
+ qt_shared_shaders()->insert(context, p = new QGLEngineSharedShaders(context));
}
return p;
}
-const char* QGLEngineShaderManager::qglEngineShaderSourceCode[] = {
+const char* QGLEngineSharedShaders::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
};
-QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
- : ctx(context),
- shaderProgNeedsChanging(true),
- srcPixelType(Qt::NoBrush),
- useGlobalOpacity(false),
- maskType(NoMask),
- useTextureCoords(false),
- compositionMode(QPainter::CompositionMode_SourceOver),
- blitShaderProg(0),
- simpleShaderProg(0),
- currentShaderProg(0)
+QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
+ : ctxGuard(context)
+ , blitShaderProg(0)
+ , simpleShaderProg(0)
{
- memset(compiledShaders, 0, sizeof(compiledShaders));
/*
Rather than having the shader source array statically initialised, it is initialised
@@ -98,13 +85,14 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
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 qglEngineShaderSourceCodePopulated = false;
- if (!qglEngineShaderSourceCodePopulated) {
+ static bool snippetsPopulated = false;
+ if (!snippetsPopulated) {
- const char** code = qglEngineShaderSourceCode; // shortcut
+ const char** code = qShaderSnippets; // shortcut
code[MainVertexShader] = qglslMainVertexShader;
code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader;
+ code[MainWithTexCoordsAndOpacityVertexShader] = qglslMainWithTexCoordsAndOpacityVertexShader;
code[UntransformedPositionVertexShader] = qglslUntransformedPositionVertexShader;
code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader;
@@ -127,10 +115,12 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
code[MainFragmentShader_C] = qglslMainFragmentShader_C;
code[MainFragmentShader_O] = qglslMainFragmentShader_O;
code[MainFragmentShader] = qglslMainFragmentShader;
+ code[MainFragmentShader_ImageArrays] = qglslMainFragmentShader_ImageArrays;
code[ImageSrcFragmentShader] = qglslImageSrcFragmentShader;
code[ImageSrcWithPatternFragmentShader] = qglslImageSrcWithPatternFragmentShader;
code[NonPremultipliedImageSrcFragmentShader] = qglslNonPremultipliedImageSrcFragmentShader;
+ code[CustomImageSrcFragmentShader] = qglslCustomSrcFragmentShader; // Calls "customShader", which must be appended
code[SolidBrushSrcFragmentShader] = qglslSolidBrushSrcFragmentShader;
code[TextureBrushSrcFragmentShader] = qglslTextureBrushSrcFragmentShader;
code[TextureBrushSrcWithPatternFragmentShader] = qglslTextureBrushSrcWithPatternFragmentShader;
@@ -140,10 +130,13 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
code[ConicalGradientBrushSrcFragmentShader] = qglslConicalGradientBrushSrcFragmentShader;
code[ShockingPinkSrcFragmentShader] = qglslShockingPinkSrcFragmentShader;
+ code[NoMaskFragmentShader] = "";
code[MaskFragmentShader] = qglslMaskFragmentShader;
- code[RgbMaskFragmentShader] = ""; //###
+ code[RgbMaskFragmentShaderPass1] = qglslRgbMaskFragmentShaderPass1;
+ code[RgbMaskFragmentShaderPass2] = qglslRgbMaskFragmentShaderPass2;
code[RgbMaskWithGammaFragmentShader] = ""; //###
+ code[NoCompositionModeFragmentShader] = "";
code[MultiplyCompositionModeFragmentShader] = ""; //###
code[ScreenCompositionModeFragmentShader] = ""; //###
code[OverlayCompositionModeFragmentShader] = ""; //###
@@ -158,29 +151,36 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
#if defined(QT_DEBUG)
// Check that all the elements have been filled:
- for (int i = 0; i < TotalShaderCount; ++i) {
- if (qglEngineShaderSourceCode[i] == 0) {
- int enumIndex = staticMetaObject.indexOfEnumerator("ShaderName");
- QMetaEnum m = staticMetaObject.enumerator(enumIndex);
-
- qCritical() << "qglEngineShaderSourceCode: Source for" << m.valueToKey(i)
- << "(shader" << i << ") missing!";
+ 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
- qglEngineShaderSourceCodePopulated = true;
+ snippetsPopulated = true;
}
+ QGLShader* fragShader;
+ QGLShader* vertexShader;
+ QByteArray source;
+
// Compile up the simple shader:
- simpleShaderProg = new QGLShaderProgram(ctx, this);
- compileNamedShader(MainVertexShader, QGLShader::PartialVertexShader);
- compileNamedShader(PositionOnlyVertexShader, QGLShader::PartialVertexShader);
- compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader);
- compileNamedShader(ShockingPinkSrcFragmentShader, QGLShader::PartialFragmentShader);
- simpleShaderProg->addShader(compiledShaders[MainVertexShader]);
- simpleShaderProg->addShader(compiledShaders[PositionOnlyVertexShader]);
- simpleShaderProg->addShader(compiledShaders[MainFragmentShader]);
- simpleShaderProg->addShader(compiledShaders[ShockingPinkSrcFragmentShader]);
+ source.clear();
+ source.append(qShaderSnippets[MainVertexShader]);
+ source.append(qShaderSnippets[PositionOnlyVertexShader]);
+ vertexShader = new QGLShader(QGLShader::Vertex, context, this);
+ vertexShader->compileSourceCode(source);
+
+ source.clear();
+ source.append(qShaderSnippets[MainFragmentShader]);
+ source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
+ fragShader = new QGLShader(QGLShader::Fragment, context, this);
+ fragShader->compileSourceCode(source);
+
+ simpleShaderProg = new QGLShaderProgram(context, this);
+ simpleShaderProg->addShader(vertexShader);
+ simpleShaderProg->addShader(fragShader);
simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
simpleShaderProg->link();
if (!simpleShaderProg->isLinked()) {
@@ -189,27 +189,177 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
}
// Compile the blit shader:
- blitShaderProg = new QGLShaderProgram(ctx, this);
- compileNamedShader(MainWithTexCoordsVertexShader, QGLShader::PartialVertexShader);
- compileNamedShader(UntransformedPositionVertexShader, QGLShader::PartialVertexShader);
- compileNamedShader(MainFragmentShader, QGLShader::PartialFragmentShader);
- compileNamedShader(ImageSrcFragmentShader, QGLShader::PartialFragmentShader);
- blitShaderProg->addShader(compiledShaders[MainWithTexCoordsVertexShader]);
- blitShaderProg->addShader(compiledShaders[UntransformedPositionVertexShader]);
- blitShaderProg->addShader(compiledShaders[MainFragmentShader]);
- blitShaderProg->addShader(compiledShaders[ImageSrcFragmentShader]);
+ source.clear();
+ source.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
+ source.append(qShaderSnippets[UntransformedPositionVertexShader]);
+ vertexShader = new QGLShader(QGLShader::Vertex, context, this);
+ vertexShader->compileSourceCode(source);
+
+ source.clear();
+ source.append(qShaderSnippets[MainFragmentShader]);
+ source.append(qShaderSnippets[ImageSrcFragmentShader]);
+ fragShader = new QGLShader(QGLShader::Fragment, context, this);
+ fragShader->compileSourceCode(source);
+
+ blitShaderProg = new QGLShaderProgram(context, this);
+ 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()) {
qCritical() << "Errors linking blit shader:"
- << blitShaderProg->log();
+ << simpleShaderProg->log();
}
+
+}
+
+#if defined (QT_DEBUG)
+QByteArray QGLEngineSharedShaders::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.
+QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineShaderProg &prog)
+{
+ for (int i = 0; i < cachedPrograms.size(); ++i) {
+ QGLEngineShaderProg *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);
+ return cachedProg;
+ }
+ }
+
+ QByteArray source;
+ source.append(qShaderSnippets[prog.mainFragShader]);
+ source.append(qShaderSnippets[prog.srcPixelFragShader]);
+ if (prog.srcPixelFragShader == CustomImageSrcFragmentShader)
+ source.append(prog.customStageSource);
+ if (prog.compositionFragShader)
+ source.append(qShaderSnippets[prog.compositionFragShader]);
+ if (prog.maskFragShader)
+ source.append(qShaderSnippets[prog.maskFragShader]);
+ QGLShader* fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this);
+ fragShader->compileSourceCode(source);
+
+ source.clear();
+ source.append(qShaderSnippets[prog.mainVertexShader]);
+ source.append(qShaderSnippets[prog.positionVertexShader]);
+ QGLShader* vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this);
+ vertexShader->compileSourceCode(source);
+
+#if defined(QT_DEBUG)
+ // Name the shaders for easier debugging
+ QByteArray description;
+ 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));
+
+ 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
+
+ QGLEngineShaderProg* newProg = new QGLEngineShaderProg(prog);
+
+ // If the shader program's not found in the cache, create it now.
+ newProg->program = new QGLShaderProgram(ctxGuard.context(), this);
+ newProg->program->addShader(vertexShader);
+ newProg->program->addShader(fragShader);
+
+ // We have to bind the vertex attribute names before the program is linked:
+ newProg->program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ if (newProg->useTextureCoords)
+ newProg->program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+ if (newProg->useOpacityAttribute)
+ newProg->program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR);
+
+ newProg->program->link();
+ if (!newProg->program->isLinked()) {
+ QLatin1String none("none");
+ QLatin1String br("\n");
+ QString error;
+ error = QLatin1String("Shader program failed to link,")
+#if defined(QT_DEBUG)
+ + br
+ + QLatin1String(" Shaders Used:") + br
+ + QLatin1String(" ") + vertexShader->objectName() + QLatin1String(": ") + br
+ + QLatin1String(vertexShader->sourceCode()) + br
+ + QLatin1String(" ") + fragShader->objectName() + QLatin1String(": ") + br
+ + QLatin1String(fragShader->sourceCode()) + br
+#endif
+ + QLatin1String(" Error Log:\n")
+ + QLatin1String(" ") + newProg->program->log();
+ qWarning() << error;
+ delete newProg; // Deletes the QGLShaderProgram in it's destructor
+ newProg = 0;
+ }
+ else {
+ 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);
+ }
+
+ return newProg;
+}
+
+void QGLEngineSharedShaders::cleanupCustomStage(QGLCustomShaderStage* stage)
+{
+ // Remove any shader programs which has this as the custom shader src:
+ for (int i = 0; i < cachedPrograms.size(); ++i) {
+ QGLEngineShaderProg *cachedProg = cachedPrograms[i];
+ if (cachedProg->customStageSource == stage->source()) {
+ delete cachedProg;
+ cachedPrograms.removeAt(i);
+ i--;
+ }
+ }
+}
+
+
+QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
+ : ctx(context),
+ shaderProgNeedsChanging(true),
+ srcPixelType(Qt::NoBrush),
+ opacityMode(NoOpacity),
+ maskType(NoMask),
+ compositionMode(QPainter::CompositionMode_SourceOver),
+ customSrcStage(0),
+ currentShaderProg(0)
+{
+ sharedShaders = QGLEngineSharedShaders::shadersForContext(context);
+ connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot()));
}
QGLEngineShaderManager::~QGLEngineShaderManager()
{
//###
+ removeCustomStage();
}
uint QGLEngineShaderManager::getUniformLocation(Uniform id)
@@ -272,21 +422,12 @@ void QGLEngineShaderManager::setSrcPixelType(PixelSrcType type)
shaderProgNeedsChanging = true; //###
}
-void QGLEngineShaderManager::setTextureCoordsEnabled(bool enabled)
+void QGLEngineShaderManager::setOpacityMode(OpacityMode mode)
{
- if (useTextureCoords == enabled)
+ if (opacityMode == mode)
return;
- useTextureCoords = enabled;
- shaderProgNeedsChanging = true; //###
-}
-
-void QGLEngineShaderManager::setUseGlobalOpacity(bool useOpacity)
-{
- if (useGlobalOpacity == useOpacity)
- return;
-
- useGlobalOpacity = useOpacity;
+ opacityMode = mode;
shaderProgNeedsChanging = true; //###
}
@@ -308,6 +449,22 @@ void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode)
shaderProgNeedsChanging = true; //###
}
+void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage)
+{
+ if (customSrcStage)
+ removeCustomStage();
+ customSrcStage = stage;
+ shaderProgNeedsChanging = true;
+}
+
+void QGLEngineShaderManager::removeCustomStage()
+{
+ if (customSrcStage)
+ customSrcStage->setInactive();
+ customSrcStage = 0;
+ shaderProgNeedsChanging = true;
+}
+
QGLShaderProgram* QGLEngineShaderManager::currentProgram()
{
return currentShaderProg->program;
@@ -315,12 +472,12 @@ QGLShaderProgram* QGLEngineShaderManager::currentProgram()
QGLShaderProgram* QGLEngineShaderManager::simpleProgram()
{
- return simpleShaderProg;
+ return sharedShaders->simpleProgram();
}
QGLShaderProgram* QGLEngineShaderManager::blitProgram()
{
- return blitShaderProg;
+ return sharedShaders->blitProgram();
}
@@ -332,247 +489,197 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
if (!shaderProgNeedsChanging)
return false;
+ bool useCustomSrc = customSrcStage != 0;
+ if (useCustomSrc && srcPixelType != QGLEngineShaderManager::ImageSrc && srcPixelType != Qt::TexturePattern) {
+ useCustomSrc = false;
+ qWarning("QGLEngineShaderManager - Ignoring custom shader stage for non image src");
+ }
+
QGLEngineShaderProg requiredProgram;
- requiredProgram.program = 0;
- // Choose vertex shader main function
- QGLEngineShaderManager::ShaderName mainVertexShaderName = InvalidShaderName;
- if (useTextureCoords)
- mainVertexShaderName = MainWithTexCoordsVertexShader;
- else
- mainVertexShaderName = MainVertexShader;
- compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader);
- requiredProgram.mainVertexShader = compiledShaders[mainVertexShaderName];
+ bool texCoords = false;
// Choose vertex shader shader position function (which typically also sets
// varyings) and the source pixel (srcPixel) fragment shader function:
- QGLEngineShaderManager::ShaderName positionVertexShaderName = InvalidShaderName;
- QGLEngineShaderManager::ShaderName srcPixelFragShaderName = InvalidShaderName;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::InvalidSnippetName;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::InvalidSnippetName;
bool isAffine = brushTransform.isAffine();
if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) {
if (isAffine)
- positionVertexShaderName = AffinePositionWithPatternBrushVertexShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader;
else
- positionVertexShaderName = PositionWithPatternBrushVertexShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionWithPatternBrushVertexShader;
- srcPixelFragShaderName = PatternBrushSrcFragmentShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::PatternBrushSrcFragmentShader;
}
else switch (srcPixelType) {
default:
case Qt::NoBrush:
- qCritical("QGLEngineShaderManager::useCorrectShaderProg() - I'm scared, Qt::NoBrush style is set");
+ qFatal("QGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set");
break;
case QGLEngineShaderManager::ImageSrc:
- srcPixelFragShaderName = ImageSrcFragmentShader;
- positionVertexShaderName = PositionOnlyVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ texCoords = true;
+ break;
+ case QGLEngineShaderManager::NonPremultipliedImageSrc:
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ texCoords = true;
break;
case QGLEngineShaderManager::PatternSrc:
- srcPixelFragShaderName = ImageSrcWithPatternFragmentShader;
- positionVertexShaderName = PositionOnlyVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ImageSrcWithPatternFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
+ texCoords = true;
break;
case QGLEngineShaderManager::TextureSrcWithPattern:
- srcPixelFragShaderName = TextureBrushSrcWithPatternFragmentShader;
- positionVertexShaderName = isAffine ? AffinePositionWithTextureBrushVertexShader
- : PositionWithTextureBrushVertexShader;
- break;
- case QGLEngineShaderManager::NonPremultipliedImageSrc:
- srcPixelFragShaderName = NonPremultipliedImageSrcFragmentShader;
- positionVertexShaderName = PositionOnlyVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
break;
case Qt::SolidPattern:
- srcPixelFragShaderName = SolidBrushSrcFragmentShader;
- positionVertexShaderName = PositionOnlyVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::SolidBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = QGLEngineSharedShaders::PositionOnlyVertexShader;
break;
case Qt::LinearGradientPattern:
- srcPixelFragShaderName = LinearGradientBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? AffinePositionWithLinearGradientBrushVertexShader
- : PositionWithLinearGradientBrushVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader;
break;
case Qt::ConicalGradientPattern:
- srcPixelFragShaderName = ConicalGradientBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? AffinePositionWithConicalGradientBrushVertexShader
- : PositionWithConicalGradientBrushVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader;
break;
case Qt::RadialGradientPattern:
- srcPixelFragShaderName = RadialGradientBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? AffinePositionWithRadialGradientBrushVertexShader
- : PositionWithRadialGradientBrushVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader;
break;
case Qt::TexturePattern:
- srcPixelFragShaderName = TextureBrushSrcFragmentShader;
- positionVertexShaderName = isAffine ? AffinePositionWithTextureBrushVertexShader
- : PositionWithTextureBrushVertexShader;
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::TextureBrushSrcFragmentShader;
+ requiredProgram.positionVertexShader = isAffine ? QGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader
+ : QGLEngineSharedShaders::PositionWithTextureBrushVertexShader;
break;
};
- compileNamedShader(positionVertexShaderName, QGLShader::PartialVertexShader);
- compileNamedShader(srcPixelFragShaderName, QGLShader::PartialFragmentShader);
- requiredProgram.positionVertexShader = compiledShaders[positionVertexShaderName];
- requiredProgram.srcPixelFragShader = compiledShaders[srcPixelFragShaderName];
+ if (useCustomSrc) {
+ requiredProgram.srcPixelFragShader = QGLEngineSharedShaders::CustomImageSrcFragmentShader;
+ requiredProgram.customStageSource = customSrcStage->source();
+ }
const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus;
const bool hasMask = maskType != QGLEngineShaderManager::NoMask;
// Choose fragment shader main function:
- QGLEngineShaderManager::ShaderName mainFragShaderName;
-
- if (hasCompose && hasMask && useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_CMO;
- if (hasCompose && hasMask && !useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_CM;
- if (!hasCompose && hasMask && useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_MO;
- if (!hasCompose && hasMask && !useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_M;
- if (hasCompose && !hasMask && useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_CO;
- if (hasCompose && !hasMask && !useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_C;
- if (!hasCompose && !hasMask && useGlobalOpacity)
- mainFragShaderName = MainFragmentShader_O;
- if (!hasCompose && !hasMask && !useGlobalOpacity)
- mainFragShaderName = MainFragmentShader;
-
- compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader);
- requiredProgram.mainFragShader = compiledShaders[mainFragShaderName];
+ if (opacityMode == AttributeOpacity) {
+ Q_ASSERT(!hasCompose && !hasMask);
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_ImageArrays;
+ } else {
+ bool useGlobalOpacity = (opacityMode == UniformOpacity);
+ if (hasCompose && hasMask && useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CMO;
+ if (hasCompose && hasMask && !useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CM;
+ if (!hasCompose && hasMask && useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_MO;
+ if (!hasCompose && hasMask && !useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_M;
+ if (hasCompose && !hasMask && useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_CO;
+ if (hasCompose && !hasMask && !useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_C;
+ if (!hasCompose && !hasMask && useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader_O;
+ if (!hasCompose && !hasMask && !useGlobalOpacity)
+ requiredProgram.mainFragShader = QGLEngineSharedShaders::MainFragmentShader;
+ }
if (hasMask) {
- QGLEngineShaderManager::ShaderName maskShaderName = QGLEngineShaderManager::InvalidShaderName;
- if (maskType == PixelMask)
- maskShaderName = MaskFragmentShader;
- else if (maskType == SubPixelMask)
- maskShaderName = RgbMaskFragmentShader;
- else if (maskType == SubPixelWithGammaMask)
- maskShaderName = RgbMaskWithGammaFragmentShader;
- else
+ if (maskType == PixelMask) {
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::MaskFragmentShader;
+ texCoords = true;
+ } else if (maskType == SubPixelMaskPass1) {
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass1;
+ texCoords = true;
+ } else if (maskType == SubPixelMaskPass2) {
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskFragmentShaderPass2;
+ texCoords = true;
+ } else if (maskType == SubPixelWithGammaMask) {
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::RgbMaskWithGammaFragmentShader;
+ texCoords = true;
+ } else {
qCritical("QGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type");
-
- compileNamedShader(maskShaderName, QGLShader::PartialFragmentShader);
- requiredProgram.maskFragShader = compiledShaders[maskShaderName];
+ }
+ } else {
+ requiredProgram.maskFragShader = QGLEngineSharedShaders::NoMaskFragmentShader;
}
- else
- requiredProgram.maskFragShader = 0;
if (hasCompose) {
- QGLEngineShaderManager::ShaderName compositionShaderName = QGLEngineShaderManager::InvalidShaderName;
switch (compositionMode) {
case QPainter::CompositionMode_Multiply:
- compositionShaderName = MultiplyCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::MultiplyCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Screen:
- compositionShaderName = ScreenCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ScreenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Overlay:
- compositionShaderName = OverlayCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::OverlayCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Darken:
- compositionShaderName = DarkenCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::DarkenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Lighten:
- compositionShaderName = LightenCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::LightenCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_ColorDodge:
- compositionShaderName = ColorDodgeCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_ColorBurn:
- compositionShaderName = ColorBurnCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_HardLight:
- compositionShaderName = HardLightCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::HardLightCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_SoftLight:
- compositionShaderName = SoftLightCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::SoftLightCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Difference:
- compositionShaderName = DifferenceCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::DifferenceCompositionModeFragmentShader;
break;
case QPainter::CompositionMode_Exclusion:
- compositionShaderName = ExclusionCompositionModeFragmentShader;
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::ExclusionCompositionModeFragmentShader;
break;
default:
qWarning("QGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode");
}
- compileNamedShader(compositionShaderName, QGLShader::PartialFragmentShader);
- requiredProgram.compositionFragShader = compiledShaders[compositionShaderName];
+ } else {
+ requiredProgram.compositionFragShader = QGLEngineSharedShaders::NoCompositionModeFragmentShader;
}
- else
- requiredProgram.compositionFragShader = 0;
-
- // At this point, requiredProgram is fully populated so try to find the program in the cache
- for (int i = 0; i < cachedPrograms.size(); ++i) {
- QGLEngineShaderProg &prog = cachedPrograms[i];
- if ( (prog.mainVertexShader == requiredProgram.mainVertexShader)
- && (prog.positionVertexShader == requiredProgram.positionVertexShader)
- && (prog.mainFragShader == requiredProgram.mainFragShader)
- && (prog.srcPixelFragShader == requiredProgram.srcPixelFragShader)
- && (prog.compositionFragShader == requiredProgram.compositionFragShader) )
- {
- currentShaderProg = &prog;
- currentShaderProg->program->enable();
- shaderProgNeedsChanging = false;
- return true;
- }
+ // Choose vertex shader main function
+ if (opacityMode == AttributeOpacity) {
+ Q_ASSERT(texCoords);
+ requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader;
+ } else if (texCoords) {
+ requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainWithTexCoordsVertexShader;
+ } else {
+ requiredProgram.mainVertexShader = QGLEngineSharedShaders::MainVertexShader;
}
+ requiredProgram.useTextureCoords = texCoords;
+ requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity);
- // Shader program not found in cache, create it now.
- requiredProgram.program = new QGLShaderProgram(ctx, this);
- requiredProgram.program->addShader(requiredProgram.mainVertexShader);
- requiredProgram.program->addShader(requiredProgram.positionVertexShader);
- requiredProgram.program->addShader(requiredProgram.mainFragShader);
- requiredProgram.program->addShader(requiredProgram.srcPixelFragShader);
- requiredProgram.program->addShader(requiredProgram.maskFragShader);
- requiredProgram.program->addShader(requiredProgram.compositionFragShader);
-
- // We have to bind the vertex attribute names before the program is linked:
- requiredProgram.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
- if (useTextureCoords)
- requiredProgram.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+ // At this point, requiredProgram is fully populated so try to find the program in the cache
+ currentShaderProg = sharedShaders->findProgramInCache(requiredProgram);
- requiredProgram.program->link();
- if (!requiredProgram.program->isLinked()) {
- QString error;
- qWarning() << "Shader program failed to link,"
-#if defined(QT_DEBUG)
- << '\n'
- << " Shaders Used:" << '\n'
- << " mainVertexShader = " << requiredProgram.mainVertexShader->objectName() << '\n'
- << " positionVertexShader = " << requiredProgram.positionVertexShader->objectName() << '\n'
- << " mainFragShader = " << requiredProgram.mainFragShader->objectName() << '\n'
- << " srcPixelFragShader = " << requiredProgram.srcPixelFragShader->objectName() << '\n'
- << " maskFragShader = " << requiredProgram.maskFragShader->objectName() << '\n'
- << " compositionFragShader = "<< requiredProgram.compositionFragShader->objectName() << '\n'
-#endif
- << " Error Log:" << '\n'
- << " " << requiredProgram.program->log();
- qWarning() << error;
- }
- else {
- cachedPrograms.append(requiredProgram);
- // taking the address here is safe since
- // cachePrograms isn't resized anywhere else
- currentShaderProg = &cachedPrograms.last();
- currentShaderProg->program->enable();
+ if (currentShaderProg) {
+ currentShaderProg->program->bind();
+ if (useCustomSrc)
+ customSrcStage->setUniforms(currentShaderProg->program);
}
+
shaderProgNeedsChanging = false;
return true;
}
-void QGLEngineShaderManager::compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type)
-{
- if (compiledShaders[name])
- return;
-
- QGLShader *newShader = new QGLShader(type, ctx, this);
- newShader->compile(qglEngineShaderSourceCode[name]);
-
-#if defined(QT_DEBUG)
- // Name the shader for easier debugging
- QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("ShaderName"));
- newShader->setObjectName(QLatin1String(m.valueToKey(name)));
-#endif
-
- compiledShaders[name] = newShader;
-}
-
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index b31499893..50c14326d 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -142,7 +142,8 @@
Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)":
qglslMaskFragmentShader
- qglslRgbMaskFragmentShader
+ qglslRgbMaskFragmentShaderPass1
+ qglslRgbMaskFragmentShaderPass2
qglslRgbMaskWithGammaFragmentShader
Composition modes are "qcolorp vec4 compose(qcolorp vec4 src)":
@@ -199,19 +200,23 @@
O = Global Opacity
- CUSTOM SHADER CODE (idea, depricated)
+ 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
- (QGLCustomizedShader). The shader will implement a pre-defined method name
- which Qt's fragment pipeline will call. There are two different hooks which
- can be implemented as custom shader code:
+ (QGLCustomShaderStage). 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)
- mediump vec4 customShader(sampler2d src, vec2 srcCoords)
- mediump vec4 customShaderWithDest(sampler2d dest, sampler2d src, vec2 srcCoords)
+ 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 QGLENGINE_SHADER_MANAGER_H
@@ -221,6 +226,7 @@
#include <QGLShaderProgram>
#include <QPainter>
#include <private/qgl_p.h>
+#include <private/qglcustomshaderstage_p.h>
QT_BEGIN_HEADER
@@ -229,19 +235,6 @@ QT_BEGIN_NAMESPACE
QT_MODULE(OpenGL)
-struct QGLEngineShaderProg
-{
- QGLShader* mainVertexShader;
- QGLShader* positionVertexShader;
- QGLShader* mainFragShader;
- QGLShader* srcPixelFragShader;
- QGLShader* maskFragShader; // Can be null for no mask
- QGLShader* compositionFragShader; // Can be null for GL-handled mode
- QGLShaderProgram* program;
-
- QVector<uint> uniformLocations;
-};
-
/*
struct QGLEngineCachedShaderProg
{
@@ -259,68 +252,21 @@ struct QGLEngineCachedShaderProg
static const GLuint QT_VERTEX_COORDS_ATTR = 0;
static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
+static const GLuint QT_OPACITY_ATTR = 2;
+
+class QGLEngineShaderProg;
-class QGLEngineShaderManager : public QObject
+class QGLEngineSharedShaders : public QObject
{
Q_OBJECT
public:
- QGLEngineShaderManager(QGLContext* context);
- ~QGLEngineShaderManager();
-
- enum MaskType {NoMask, PixelMask, SubPixelMask, 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,
- PmvMatrix,
- MaskTexture,
- FragmentColor,
- LinearData,
- Angle,
- HalfViewportSize,
- Fmp,
- Fmp2MRadius2,
- Inverse2Fmp2MRadius2,
- InvertedTextureSize,
- BrushTransform,
- BrushTexture,
- NumUniforms
- };
- // There are optimisations 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(const QTransform &transform);
- void setSrcPixelType(Qt::BrushStyle);
- void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images
- void setTextureCoordsEnabled(bool); // For images & text glyphs
- void setUseGlobalOpacity(bool);
- void setMaskType(MaskType);
- void setCompositionMode(QPainter::CompositionMode);
-
- uint 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
-
- QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
- QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
- QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
-
- static QGLEngineShaderManager *managerForContext(const QGLContext *context);
-
- enum ShaderName {
+ enum SnippetName {
MainVertexShader,
MainWithTexCoordsVertexShader,
+ MainWithTexCoordsAndOpacityVertexShader,
+ // UntransformedPositionVertexShader must be first in the list:
UntransformedPositionVertexShader,
PositionOnlyVertexShader,
PositionWithPatternBrushVertexShader,
@@ -334,6 +280,7 @@ public:
AffinePositionWithRadialGradientBrushVertexShader,
AffinePositionWithTextureBrushVertexShader,
+ // MainFragmentShader_CMO must be first in the list:
MainFragmentShader_CMO,
MainFragmentShader_CM,
MainFragmentShader_MO,
@@ -342,10 +289,13 @@ public:
MainFragmentShader_C,
MainFragmentShader_O,
MainFragmentShader,
+ MainFragmentShader_ImageArrays,
+ // ImageSrcFragmentShader must be first in the list::
ImageSrcFragmentShader,
ImageSrcWithPatternFragmentShader,
NonPremultipliedImageSrcFragmentShader,
+ CustomImageSrcFragmentShader,
SolidBrushSrcFragmentShader,
TextureBrushSrcFragmentShader,
TextureBrushSrcWithPatternFragmentShader,
@@ -355,10 +305,15 @@ public:
ConicalGradientBrushSrcFragmentShader,
ShockingPinkSrcFragmentShader,
+ // NoMaskFragmentShader must be first in the list:
+ NoMaskFragmentShader,
MaskFragmentShader,
- RgbMaskFragmentShader,
+ RgbMaskFragmentShaderPass1,
+ RgbMaskFragmentShaderPass2,
RgbMaskWithGammaFragmentShader,
+ // NoCompositionModeFragmentShader must be first in the list:
+ NoCompositionModeFragmentShader,
MultiplyCompositionModeFragmentShader,
ScreenCompositionModeFragmentShader,
OverlayCompositionModeFragmentShader,
@@ -371,9 +326,12 @@ public:
DifferenceCompositionModeFragmentShader,
ExclusionCompositionModeFragmentShader,
- TotalShaderCount, InvalidShaderName
+ 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
@@ -385,10 +343,139 @@ public:
const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader;
*/
-#if defined (QT_DEBUG)
- Q_ENUMS(ShaderName)
-#endif
+ QGLEngineSharedShaders(const QGLContext *context);
+
+ QGLShaderProgram *simpleProgram() { return simpleShaderProg; }
+ QGLShaderProgram *blitProgram() { return blitShaderProg; }
+ // Compile the program if it's not already in the cache, return the item in the cache.
+ QGLEngineShaderProg *findProgramInCache(const QGLEngineShaderProg &prog);
+ // Compile the custom shader if it's not already in the cache, return the item in the cache.
+
+ static QGLEngineSharedShaders *shadersForContext(const QGLContext *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(QGLCustomShaderStage* stage);
+
+signals:
+ void shaderProgNeedsChanging();
+private:
+ QGLSharedResourceGuard ctxGuard;
+ QGLShaderProgram *blitShaderProg;
+ QGLShaderProgram *simpleShaderProg;
+ QList<QGLEngineShaderProg*> cachedPrograms;
+
+ static const char* qShaderSnippets[TotalSnippetCount];
+};
+
+
+class QGLEngineShaderProg
+{
+public:
+ QGLEngineShaderProg() : program(0) {}
+
+ ~QGLEngineShaderProg() {
+ if (program)
+ delete program;
+ }
+
+ QGLEngineSharedShaders::SnippetName mainVertexShader;
+ QGLEngineSharedShaders::SnippetName positionVertexShader;
+ QGLEngineSharedShaders::SnippetName mainFragShader;
+ QGLEngineSharedShaders::SnippetName srcPixelFragShader;
+ QGLEngineSharedShaders::SnippetName maskFragShader;
+ QGLEngineSharedShaders::SnippetName compositionFragShader;
+
+ QByteArray customStageSource; //TODO: Decent cache key for custom stages
+ QGLShaderProgram* program;
+
+ QVector<uint> uniformLocations;
+
+ bool useTextureCoords;
+ bool useOpacityAttribute;
+
+ bool operator==(const QGLEngineShaderProg& 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_OPENGL_EXPORT QGLEngineShaderManager : public QObject
+{
+ Q_OBJECT
+public:
+ QGLEngineShaderManager(QGLContext* context);
+ ~QGLEngineShaderManager();
+
+ 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,
+ PmvMatrix,
+ MaskTexture,
+ FragmentColor,
+ LinearData,
+ Angle,
+ HalfViewportSize,
+ Fmp,
+ Fmp2MRadius2,
+ Inverse2Fmp2MRadius2,
+ InvertedTextureSize,
+ BrushTransform,
+ BrushTexture,
+ NumUniforms
+ };
+
+ enum OpacityMode {
+ NoOpacity,
+ UniformOpacity,
+ AttributeOpacity
+ };
+
+ // There are optimisations 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(const QTransform &transform);
+ 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(QGLCustomShaderStage* stage);
+ void removeCustomStage();
+
+ uint 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
+
+ QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
+ QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
+ QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
+
+ QGLEngineSharedShaders* sharedShaders;
+
+private slots:
+ void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; }
private:
QGLContext* ctx;
@@ -397,23 +484,12 @@ private:
// Current state variables which influence the choice of shader:
QTransform brushTransform;
int srcPixelType;
- bool useGlobalOpacity;
+ OpacityMode opacityMode;
MaskType maskType;
- bool useTextureCoords;
QPainter::CompositionMode compositionMode;
+ QGLCustomShaderStage* customSrcStage;
- QGLShaderProgram* blitShaderProg;
- QGLShaderProgram* simpleShaderProg;
- QGLEngineShaderProg* currentShaderProg;
-
- // TODO: Possibly convert to a LUT
- QList<QGLEngineShaderProg> cachedPrograms;
-
- QGLShader* compiledShaders[TotalShaderCount];
-
- void compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type);
-
- static const char* qglEngineShaderSourceCode[TotalShaderCount];
+ QGLEngineShaderProg* currentShaderProg;
};
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h
index c80d6e176..2407979e3 100644
--- a/src/opengl/gl2paintengineex/qglengineshadersource_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -73,8 +73,8 @@ static const char* const qglslMainVertexShader = "\
}";
static const char* const qglslMainWithTexCoordsVertexShader = "\
- attribute mediump vec2 textureCoordArray; \
- varying mediump vec2 textureCoords; \
+ attribute highp vec2 textureCoordArray; \
+ varying highp vec2 textureCoords; \
uniform highp float depth;\
void setPosition();\
void main(void) \
@@ -84,6 +84,20 @@ static const char* const qglslMainWithTexCoordsVertexShader = "\
textureCoords = textureCoordArray; \
}";
+static const char* const qglslMainWithTexCoordsAndOpacityVertexShader = "\
+ attribute highp vec2 textureCoordArray; \
+ attribute lowp float opacityArray; \
+ varying highp vec2 textureCoords; \
+ varying lowp float opacity; \
+ uniform highp float depth; \
+ void setPosition(); \
+ void main(void) \
+ { \
+ setPosition(); \
+ gl_Position.z = depth * gl_Position.w; \
+ textureCoords = textureCoordArray; \
+ opacity = opacityArray; \
+ }";
static const char* const qglslPositionOnlyVertexShader = "\
attribute highp vec4 vertexCoordsArray;\
@@ -105,9 +119,9 @@ static const char* const qglslPositionWithPatternBrushVertexShader = "\
attribute highp vec4 vertexCoordsArray; \
uniform highp mat4 pmvMatrix; \
uniform mediump vec2 halfViewportSize; \
- uniform mediump vec2 invertedTextureSize; \
- uniform mediump mat3 brushTransform; \
- varying mediump vec2 patternTexCoords; \
+ uniform highp vec2 invertedTextureSize; \
+ uniform highp mat3 brushTransform; \
+ varying highp vec2 patternTexCoords; \
void setPosition(void) { \
gl_Position = pmvMatrix * vertexCoordsArray;\
gl_Position.xy = gl_Position.xy / gl_Position.w; \
@@ -117,16 +131,15 @@ static const char* const qglslPositionWithPatternBrushVertexShader = "\
gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \
gl_Position.w = invertedHTexCoordsZ; \
patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \
- patternTexCoords.y = -patternTexCoords.y; \
}";
static const char* const qglslAffinePositionWithPatternBrushVertexShader
= qglslPositionWithPatternBrushVertexShader;
static const char* const qglslPatternBrushSrcFragmentShader = "\
- uniform sampler2D brushTexture;\
+ uniform lowp sampler2D brushTexture;\
uniform lowp vec4 patternColor; \
- varying mediump vec2 patternTexCoords;\
+ varying highp vec2 patternTexCoords;\
lowp vec4 srcPixel() { \
return patternColor * (1.0 - texture2D(brushTexture, patternTexCoords).r); \
}\n";
@@ -139,7 +152,7 @@ static const char* const qglslPositionWithLinearGradientBrushVertexShader = "\
uniform mediump vec2 halfViewportSize; \
uniform highp vec3 linearData; \
uniform highp mat3 brushTransform; \
- varying mediump float index ; \
+ varying mediump float index; \
void setPosition() { \
gl_Position = pmvMatrix * vertexCoordsArray;\
gl_Position.xy = gl_Position.xy / gl_Position.w; \
@@ -155,7 +168,7 @@ static const char* const qglslAffinePositionWithLinearGradientBrushVertexShader
= qglslPositionWithLinearGradientBrushVertexShader;
static const char* const qglslLinearGradientBrushSrcFragmentShader = "\
- uniform sampler2D brushTexture; \
+ uniform lowp sampler2D brushTexture; \
varying mediump float index; \
lowp vec4 srcPixel() { \
mediump vec2 val = vec2(index, 0.5); \
@@ -187,7 +200,7 @@ static const char* const qglslAffinePositionWithConicalGradientBrushVertexShader
static const char* const qglslConicalGradientBrushSrcFragmentShader = "\n\
#define INVERSE_2PI 0.1591549430918953358 \n\
- uniform sampler2D brushTexture; \n\
+ uniform lowp sampler2D brushTexture; \n\
uniform mediump float angle; \
varying highp vec2 A; \
lowp vec4 srcPixel() { \
@@ -226,7 +239,7 @@ static const char* const qglslAffinePositionWithRadialGradientBrushVertexShader
= qglslPositionWithRadialGradientBrushVertexShader;
static const char* const qglslRadialGradientBrushSrcFragmentShader = "\
- uniform sampler2D brushTexture; \
+ uniform lowp sampler2D brushTexture; \
uniform highp float fmp2_m_radius2; \
uniform highp float inverse_2_fmp2_m_radius2; \
varying highp float b; \
@@ -243,9 +256,9 @@ static const char* const qglslPositionWithTextureBrushVertexShader = "\
attribute highp vec4 vertexCoordsArray; \
uniform highp mat4 pmvMatrix; \
uniform mediump vec2 halfViewportSize; \
- uniform mediump vec2 invertedTextureSize; \
- uniform mediump mat3 brushTransform; \
- varying mediump vec2 brushTextureCoords; \
+ uniform highp vec2 invertedTextureSize; \
+ uniform highp mat3 brushTransform; \
+ varying highp vec2 textureCoords; \
void setPosition(void) { \
gl_Position = pmvMatrix * vertexCoordsArray;\
gl_Position.xy = gl_Position.xy / gl_Position.w; \
@@ -254,26 +267,37 @@ static const char* const qglslPositionWithTextureBrushVertexShader = "\
mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \
gl_Position.xy = gl_Position.xy * invertedHTexCoordsZ; \
gl_Position.w = invertedHTexCoordsZ; \
- brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \
- brushTextureCoords.y = -brushTextureCoords.y; \
+ textureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \
}";
static const char* const qglslAffinePositionWithTextureBrushVertexShader
= qglslPositionWithTextureBrushVertexShader;
+#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 qglslTextureBrushSrcFragmentShader = "\
+ varying highp vec2 textureCoords; \
+ uniform lowp sampler2D brushTexture; \
+ lowp vec4 srcPixel() { \
+ return texture2D(brushTexture, fract(textureCoords)); \
+ }";
+#else
static const char* const qglslTextureBrushSrcFragmentShader = "\
- varying mediump vec2 brushTextureCoords; \
- uniform sampler2D brushTexture; \
+ varying highp vec2 textureCoords; \
+ uniform lowp sampler2D brushTexture; \
lowp vec4 srcPixel() { \
- return texture2D(brushTexture, brushTextureCoords); \
+ return texture2D(brushTexture, textureCoords); \
}";
+#endif
static const char* const qglslTextureBrushSrcWithPatternFragmentShader = "\
- varying mediump vec2 brushTextureCoords; \
+ varying highp vec2 textureCoords; \
uniform lowp vec4 patternColor; \
- uniform sampler2D brushTexture; \
+ uniform lowp sampler2D brushTexture; \
lowp vec4 srcPixel() { \
- return patternColor * (1.0 - texture2D(brushTexture, brushTextureCoords).r); \
+ return patternColor * (1.0 - texture2D(brushTexture, textureCoords).r); \
}";
// Solid Fill Brush
@@ -284,23 +308,31 @@ static const char* const qglslSolidBrushSrcFragmentShader = "\
}";
static const char* const qglslImageSrcFragmentShader = "\
- varying mediump vec2 textureCoords; \
- uniform sampler2D imageTexture; \
+ varying highp vec2 textureCoords; \
+ uniform lowp sampler2D imageTexture; \
lowp vec4 srcPixel() { \
return texture2D(imageTexture, textureCoords); \
}";
+static const char* const qglslCustomSrcFragmentShader = "\
+ varying highp vec2 textureCoords; \
+ uniform lowp sampler2D imageTexture; \
+ lowp vec4 customShader(lowp sampler2D texture, highp vec2 coords); \
+ lowp vec4 srcPixel() { \
+ return customShader(imageTexture, textureCoords); \
+ }";
+
static const char* const qglslImageSrcWithPatternFragmentShader = "\
varying highp vec2 textureCoords; \
uniform lowp vec4 patternColor; \
- uniform sampler2D imageTexture; \
+ uniform lowp sampler2D imageTexture; \
lowp vec4 srcPixel() { \
return patternColor * (1.0 - texture2D(imageTexture, textureCoords).r); \
}\n";
static const char* const qglslNonPremultipliedImageSrcFragmentShader = "\
varying highp vec2 textureCoords; \
- uniform sampler2D imageTexture; \
+ uniform lowp sampler2D imageTexture; \
lowp vec4 srcPixel() { \
lowp vec4 sample = texture2D(imageTexture, textureCoords); \
sample.rgb = sample.rgb * sample.a; \
@@ -312,6 +344,12 @@ static const char* const qglslShockingPinkSrcFragmentShader = "\
return vec4(0.98, 0.06, 0.75, 1.0); \
}";
+static const char* const qglslMainFragmentShader_ImageArrays = "\
+ varying lowp float opacity; \
+ lowp vec4 srcPixel(); \
+ void main() { \
+ gl_FragColor = srcPixel() * opacity; \
+ }";
static const char* const qglslMainFragmentShader_CMO = "\
uniform lowp float globalOpacity; \
@@ -375,13 +413,46 @@ static const char* const qglslMainFragmentShader = "\
static const char* const qglslMaskFragmentShader = "\
varying highp vec2 textureCoords;\
- uniform sampler2D maskTexture;\
+ uniform lowp sampler2D maskTexture;\
lowp vec4 applyMask(lowp vec4 src) \
{\
lowp vec4 mask = texture2D(maskTexture, textureCoords); \
return src * mask.a; \
}";
+// 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 qglslRgbMaskFragmentShaderPass1 = "\
+ varying highp vec2 textureCoords;\
+ uniform lowp sampler2D maskTexture;\
+ lowp vec4 applyMask(lowp vec4 src) \
+ {\
+ lowp vec4 mask = texture2D(maskTexture, textureCoords); \
+ return src.a * mask; \
+ }";
+
+static const char* const qglslRgbMaskFragmentShaderPass2 = "\
+ varying highp vec2 textureCoords;\
+ uniform lowp sampler2D maskTexture;\
+ lowp vec4 applyMask(lowp vec4 src) \
+ {\
+ lowp vec4 mask = texture2D(maskTexture, textureCoords); \
+ return src * mask; \
+ }";
+
/*
Left to implement:
RgbMaskFragmentShader,
diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp
index ea34f5c23..e06f15d1c 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache.cpp
+++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -57,13 +57,9 @@ QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context)
{
QGL2GradientCache *p = reinterpret_cast<QGL2GradientCache *>(qt_gradient_caches()->value(context));
if (!p) {
- QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
- if (oldContext != context)
- const_cast<QGLContext *>(context)->makeCurrent();
+ QGLShareContextScope scope(context);
p = new QGL2GradientCache;
qt_gradient_caches()->insert(context, p);
- if (oldContext && oldContext != context)
- oldContext->makeCurrent();
}
return p;
}
diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h
index f2f6ebd25..3813f39ef 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache_p.h
+++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 34f7e7af7..3fce3841a 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -62,6 +62,8 @@
and use the correct program when we really need it.
*/
+// #define QT_OPENGL_CACHE_AS_VBOS
+
#include "qpaintengineex_opengl2_p.h"
#include <string.h> //for memcpy
@@ -81,15 +83,24 @@
#include "qglengineshadermanager_p.h"
#include "qgl2pexvertexarray_p.h"
+#include "qtriangulatingstroker_p.h"
+
#include <QDebug>
QT_BEGIN_NAMESPACE
+//#define QT_GL_NO_SCISSOR_TEST
+
+static const GLuint GL_STENCIL_HIGH_BIT = 0x80;
static const GLuint QT_BRUSH_TEXTURE_UNIT = 0;
static const GLuint QT_IMAGE_TEXTURE_UNIT = 0; //Can be the same as brush texture unit
static const GLuint QT_MASK_TEXTURE_UNIT = 1;
static const GLuint QT_BACKGROUND_TEXTURE_UNIT = 2;
+#ifdef Q_WS_WIN
+extern Q_GUI_EXPORT bool qt_cleartype_enabled;
+#endif
+
class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache
{
Q_OBJECT
@@ -100,6 +111,7 @@ public:
virtual void createTextureData(int width, int height);
virtual void resizeTextureData(int width, int height);
virtual void fillTexture(const Coord &c, glyph_t glyph);
+ virtual int glyphMargin() const;
inline GLuint texture() const { return m_texture; }
@@ -122,7 +134,7 @@ public Q_SLOTS:
// since the context holding the texture is shared, and
// about to be destroyed, we have to transfer ownership
// of the texture to one of the share contexts
- ctx = const_cast<QGLContext *>(shares.at(0));
+ ctx = const_cast<QGLContext *>((ctx == shares.at(0)) ? shares.at(1) : shares.at(0));
}
}
}
@@ -148,22 +160,18 @@ QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyph
, m_height(0)
{
glGenFramebuffers(1, &m_fbo);
- connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(contextDestroyed(const QGLContext *)));
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(contextDestroyed(const QGLContext*)));
}
QGLTextureGlyphCache::~QGLTextureGlyphCache()
{
if (ctx) {
- QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
- if (oldContext != ctx)
- ctx->makeCurrent();
+ QGLShareContextScope scope(ctx);
glDeleteFramebuffers(1, &m_fbo);
if (m_width || m_height)
glDeleteTextures(1, &m_texture);
- if (oldContext && oldContext != ctx)
- oldContext->makeCurrent();
}
}
@@ -219,8 +227,15 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
pex->transferMode(BrushDrawingMode);
+#ifndef QT_OPENGL_ES_2
+ if (pex->inRenderText)
+ glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_SCISSOR_BIT);
+#endif
+
+ glDisable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
glViewport(0, 0, oldWidth, oldHeight);
@@ -233,7 +248,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);
- pex->shaderManager->blitProgram()->enable();
+ pex->shaderManager->blitProgram()->bind();
pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
pex->shaderManager->setDirty();
@@ -246,6 +261,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
#ifdef QT_OPENGL_ES_2
QDataBuffer<uchar> buffer(4*oldWidth*oldHeight);
+ buffer.resize(4*oldWidth*oldHeight);
glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
// do an in-place conversion from GL_RGBA to GL_ALPHA
@@ -266,19 +282,33 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
glViewport(0, 0, pex->width, pex->height);
- pex->updateDepthScissorTest();
+ pex->updateClipScissorTest();
+
+#ifndef QT_OPENGL_ES_2
+ if (pex->inRenderText)
+ glPopAttrib();
+#endif
}
void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
{
QImage mask = textureMapForGlyph(glyph);
+ const int maskWidth = mask.width();
+ const int maskHeight = mask.height();
+
+ if (mask.format() == QImage::Format_Mono) {
+ mask = mask.convertToFormat(QImage::Format_Indexed8);
+ for (int y = 0; y < maskHeight; ++y) {
+ uchar *src = (uchar *) mask.scanLine(y);
+ for (int x = 0; x < maskWidth; ++x)
+ src[x] = -src[x]; // convert 0 and 1 into 0 and 255
+ }
+ }
- const uint maskWidth = mask.width();
- const uint maskHeight = mask.height();
glBindTexture(GL_TEXTURE_2D, m_texture);
if (mask.format() == QImage::Format_RGB32) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, m_height - c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
} else {
#ifdef QT_OPENGL_ES2
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
@@ -292,18 +322,37 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
// by converting it to a format with four bytes per pixel. Another is to copy one line at a
// time.
- for (uint i = 0; i < maskHeight; ++i)
+ 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));
#endif
}
}
+int QGLTextureGlyphCache::glyphMargin() const
+{
+#if defined(Q_WS_MAC)
+ return 2;
+#elif defined (Q_WS_X11)
+ return 0;
+#else
+ return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
+#endif
+}
+
extern QImage qt_imageForBrush(int brushStyle, bool invert);
////////////////////////////////// Private Methods //////////////////////////////////////////
QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
{
+ delete shaderManager;
+
+ while (pathCaches.size()) {
+ QVectorPath::CacheEntry *e = *(pathCaches.constBegin());
+ e->cleanup(e->engine, e->data);
+ e->data = 0;
+ e->engine = 0;
+ }
}
void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
@@ -326,7 +375,7 @@ void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMod
}
-QColor QGL2PaintEngineExPrivate::premultiplyColor(QColor c, GLfloat opacity)
+inline QColor qt_premultiplyColor(QColor c, GLfloat opacity)
{
qreal alpha = c.alphaF() * opacity;
c.setAlphaF(alpha);
@@ -353,10 +402,9 @@ void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush)
}
-// Unless this gets used elsewhere, it's probably best to merge it into fillStencilWithVertexArray
void QGL2PaintEngineExPrivate::useSimpleShader()
{
- shaderManager->simpleProgram()->enable();
+ shaderManager->simpleProgram()->bind();
shaderManager->setDirty();
if (matrixDirty)
@@ -366,15 +414,11 @@ void QGL2PaintEngineExPrivate::useSimpleShader()
shaderManager->simpleProgram()->setUniformValue("pmvMatrix", pmvMatrix);
simpleShaderMatrixUniformDirty = false;
}
-
- if (simpleShaderDepthUniformDirty) {
- shaderManager->simpleProgram()->setUniformValue("depth", (GLfloat)q->state()->currentDepth);
- simpleShaderDepthUniformDirty = false;
- }
}
void QGL2PaintEngineExPrivate::updateBrushTexture()
{
+ Q_Q(QGL2PaintEngineEx);
// qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()");
Qt::BrushStyle style = currentBrush->style();
@@ -383,8 +427,8 @@ void QGL2PaintEngineExPrivate::updateBrushTexture()
QImage texImage = qt_imageForBrush(style, false);
glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
- ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true);
- updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
+ ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true, QGLContext::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
@@ -399,18 +443,19 @@ void QGL2PaintEngineExPrivate::updateBrushTexture()
glBindTexture(GL_TEXTURE_2D, texId);
if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient)
- updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
+ updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
else if (g->spread() == QGradient::ReflectSpread)
- updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, true);
+ updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, q->state()->renderHints & QPainter::SmoothPixmapTransform);
else
- updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, true);
+ updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform);
}
else if (style == Qt::TexturePattern) {
const QPixmap& texPixmap = currentBrush->texture();
glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
- ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, true);
- updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
+ QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
+ updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform);
+ textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1;
}
brushTextureDirty = false;
}
@@ -427,7 +472,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
QTransform brushQTransform = currentBrush->transform();
if (style == Qt::SolidPattern) {
- QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
+ QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col);
}
else {
@@ -435,9 +480,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
QPointF translationPoint;
if (style <= Qt::DiagCrossPattern) {
- translationPoint = q->state()->brushOrigin;
-
- QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
+ QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
@@ -494,16 +537,14 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else if (style == Qt::TexturePattern) {
- translationPoint = q->state()->brushOrigin;
-
const QPixmap& texPixmap = currentBrush->texture();
if (qHasPixmapTexture(*currentBrush) && currentBrush->texture().isQBitmap()) {
- QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
+ QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
}
- QSizeF invertedTextureSize( 1.0 / texPixmap.width(), 1.0 / texPixmap.height() );
+ QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height());
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::InvertedTextureSize), invertedTextureSize);
QVector2D halfViewportSize(width*0.5, height*0.5);
@@ -512,9 +553,17 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
else
qWarning("QGL2PaintEngineEx: 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());
QTransform gl_to_qt(1, 0, 0, -1, 0, height);
- QTransform inv_matrix = gl_to_qt * (brushQTransform * q->state()->matrix).inverted() * translate;
+ 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(QGLEngineShaderManager::BrushTransform), inv_matrix);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT);
@@ -528,46 +577,58 @@ void QGL2PaintEngineExPrivate::updateMatrix()
{
// qDebug("QGL2PaintEngineExPrivate::updateMatrix()");
- // We setup the Projection matrix to be the equivilant of glOrtho(0, w, h, 0, -1, 1):
- GLfloat P[4][4] = {
- {2.0/width, 0.0, 0.0, -1.0},
- {0.0, -2.0/height, 0.0, 1.0},
- {0.0, 0.0, -1.0, 0.0},
- {0.0, 0.0, 0.0, 1.0}
- };
-
+ // We set up the 4x4 transformation matrix on the vertex shaders to
+ // be the equivalent of glOrtho(0, w, h, 0, -1, 1) * transform:
+ //
+ // | 2/width 0 0 -1 | | m11 m21 0 dx |
+ // | 0 -2/height 0 1 | | m12 m22 0 dy |
+ // | 0 0 -1 0 | * | 0 0 1 0 |
+ // | 0 0 0 1 | | m13 m23 0 m33 |
+ //
+ // We expand out the multiplication to save the cost of a full 4x4
+ // matrix multiplication as most of the components are trivial.
const QTransform& transform = q->state()->matrix;
if (mode == TextDrawingMode) {
// Text drawing mode is only used for non-scaling transforms
- for (int row = 0; row < 4; ++row)
- for (int col = 0; col < 4; ++col)
- pmvMatrix[col][row] = P[row][col];
-
- pmvMatrix[3][0] += P[0][0] * qRound(transform.dx());
- pmvMatrix[3][1] += P[1][1] * qRound(transform.dy());
+ pmvMatrix[0][0] = 2.0 / width;
+ pmvMatrix[0][1] = 0.0;
+ pmvMatrix[0][2] = 0.0;
+ pmvMatrix[0][3] = 0.0;
+ pmvMatrix[1][0] = 0.0;
+ pmvMatrix[1][1] = -2.0 / height;
+ pmvMatrix[1][2] = 0.0;
+ pmvMatrix[1][3] = 0.0;
+ pmvMatrix[2][0] = 0.0;
+ pmvMatrix[2][1] = 0.0;
+ pmvMatrix[2][2] = -1.0;
+ pmvMatrix[2][3] = 0.0;
+ pmvMatrix[3][0] = pmvMatrix[0][0] * qRound(transform.dx()) - 1.0;
+ pmvMatrix[3][1] = pmvMatrix[1][1] * qRound(transform.dy()) + 1.0;
+ pmvMatrix[3][2] = 0.0;
+ pmvMatrix[3][3] = 1.0;
inverseScale = 1;
} else {
- // Use the (3x3) transform for the Model~View matrix:
- GLfloat MV[4][4] = {
- {transform.m11(), transform.m21(), 0.0, transform.dx()},
- {transform.m12(), transform.m22(), 0.0, transform.dy()},
- {0.0, 0.0, 1.0, 0.0},
- {transform.m13(), transform.m23(), 0.0, transform.m33()}
- };
-
- // NOTE: OpenGL ES works with column-major matrices, so when we multiply the matrices,
- // we also transpose them ready for GL.
- for (int row = 0; row < 4; ++row) {
- for (int col = 0; col < 4; ++col) {
- pmvMatrix[col][row] = 0.0;
-
- // P[row][n] is 0.0 for n < row
- for (int n = row; n < 4; ++n)
- pmvMatrix[col][row] += P[row][n] * MV[n][col];
- }
- }
+ qreal wfactor = 2.0 / width;
+ qreal hfactor = -2.0 / height;
+
+ pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13();
+ pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13();
+ pmvMatrix[0][2] = 0.0;
+ pmvMatrix[0][3] = transform.m13();
+ pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23();
+ pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23();
+ pmvMatrix[1][2] = 0.0;
+ pmvMatrix[1][3] = transform.m23();
+ pmvMatrix[2][0] = 0.0;
+ pmvMatrix[2][1] = 0.0;
+ pmvMatrix[2][2] = -1.0;
+ pmvMatrix[2][3] = 0.0;
+ pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33();
+ pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33();
+ pmvMatrix[3][2] = 0.0;
+ pmvMatrix[3][3] = transform.m33();
// 1/10000 == 0.0001, so we have good enough res to cover curves
// that span the entire widget...
@@ -581,6 +642,9 @@ void QGL2PaintEngineExPrivate::updateMatrix()
// The actual data has been updated so both shader program's uniforms need updating
simpleShaderMatrixUniformDirty = true;
shaderMatrixUniformDirty = true;
+
+ dasher.setInvScale(inverseScale);
+ stroker.setInvScale(inverseScale);
}
@@ -653,19 +717,18 @@ void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& s
{
// Setup for texture drawing
shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
- shaderManager->setTextureCoordsEnabled(true);
if (prepareForDraw(opaque))
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
if (pattern) {
- QColor col = premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
+ QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
}
GLfloat dx = 1.0 / textureSize.width();
GLfloat dy = 1.0 / textureSize.height();
- QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);
+ QGLRect srcTextureRect(src.left*dx, src.top*dy, src.right*dx, src.bottom*dy);
setCoords(staticVertexCoordinateArray, dest);
setCoords(staticTextureCoordinateArray, srcTextureRect);
@@ -673,7 +736,7 @@ void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& s
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
-void QGL2PaintEngineEx::sync()
+void QGL2PaintEngineEx::beginNativePainting()
{
Q_D(QGL2PaintEngineEx);
ensureActive();
@@ -696,7 +759,7 @@ void QGL2PaintEngineEx::sync()
{ mtx.dx(), mtx.dy(), 0, mtx.m33() }
};
- const QSize sz = d->drawable.size();
+ const QSize sz = d->device->size();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@@ -704,29 +767,52 @@ void QGL2PaintEngineEx::sync()
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(&mv_matrix[0][0]);
+#else
+ Q_UNUSED(ctx);
#endif
d->lastTexture = GLuint(-1);
+ d->dirtyStencilRegion = QRect(0, 0, d->width, d->height);
+ d->resetGLState();
+
+ d->shaderManager->setDirty();
+
+ d->needsSync = true;
+}
+void QGL2PaintEngineExPrivate::resetGLState()
+{
glDisable(GL_BLEND);
glActiveTexture(GL_TEXTURE0);
-
+ glDisable(GL_STENCIL_TEST);
glDisable(GL_DEPTH_TEST);
- glDepthFunc(GL_LESS);
+ glDisable(GL_SCISSOR_TEST);
glDepthMask(true);
+ glDepthFunc(GL_LESS);
glClearDepth(1);
+}
+void QGL2PaintEngineEx::endNativePainting()
+{
+ Q_D(QGL2PaintEngineEx);
d->needsSync = true;
}
+const QGLContext *QGL2PaintEngineEx::context()
+{
+ Q_D(QGL2PaintEngineEx);
+ return d->ctx;
+}
+
void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
{
if (newMode == mode)
return;
- if (mode == TextDrawingMode || mode == ImageDrawingMode) {
+ if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) {
glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glDisableVertexAttribArray(QT_OPACITY_ATTR);
lastTexture = GLuint(-1);
}
@@ -752,6 +838,16 @@ void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray);
}
+ if (newMode == ImageArrayDrawingMode) {
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_OPACITY_ATTR);
+
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
+ glVertexAttribPointer(QT_OPACITY_ATTR, 1, GL_FLOAT, GL_FALSE, 0, opacityArray.data());
+ }
+
// This needs to change when we implement high-quality anti-aliasing...
if (newMode != TextDrawingMode)
shaderManager->setMaskType(QGLEngineShaderManager::NoMask);
@@ -759,28 +855,30 @@ void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
mode = newMode;
}
-void QGL2PaintEngineExPrivate::drawOutline(const QVectorPath& path)
+struct QGL2PEVectorPathCache
{
- transferMode(BrushDrawingMode);
-
- // Might need to call updateMatrix to re-calculate inverseScale
- if (matrixDirty)
- updateMatrix();
-
- vertexCoordinateArray.clear();
- vertexCoordinateArray.addPath(path, inverseScale);
-
- if (path.hasImplicitClose()) {
- // Close the path's outline
- vertexCoordinateArray.lineToArray(path.points()[0], path.points()[1]);
- vertexCoordinateArray.stops().last() += 1;
- }
+#ifdef QT_OPENGL_CACHE_AS_VBOS
+ GLuint vbo;
+#else
+ float *vertices;
+#endif
+ int vertexCount;
+ GLenum primitiveType;
+ qreal iscale;
+};
- prepareForDraw(currentBrush->isOpaque());
- drawVertexArrays(vertexCoordinateArray, GL_LINE_STRIP);
+void qopengl2paintengine_cleanup_vectorpath(QPaintEngineEx *engine, void *data)
+{
+ QGL2PEVectorPathCache *c = (QGL2PEVectorPathCache *) data;
+#ifdef QT_OPENGL_CACHE_AS_VBOS
+ QGL2PaintEngineExPrivate *d = QGL2PaintEngineExPrivate::getData((QGL2PaintEngineEx *) engine);
+ d->unusedVBOSToClean << c->vbo;
+#else
+ qFree(c->vertices);
+#endif
+ delete c;
}
-
// Assumes everything is configured for the brush you want to use
void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
{
@@ -796,75 +894,268 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
if (path.shape() == QVectorPath::RectangleHint) {
QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y());
prepareForDraw(currentBrush->isOpaque());
-
composite(rect);
- }
- else if (path.shape() == QVectorPath::EllipseHint) {
- vertexCoordinateArray.clear();
- vertexCoordinateArray.addPath(path, inverseScale);
- prepareForDraw(currentBrush->isOpaque());
- drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
- }
- else {
+ } else if (path.isConvex()) {
+
+ if (path.isCacheable()) {
+ QVectorPath::CacheEntry *data = path.lookupCacheData(q);
+ QGL2PEVectorPathCache *cache;
+
+ if (data) {
+ cache = (QGL2PEVectorPathCache *) 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;
+#else
+ qFree(cache->vertices);
+#endif
+ cache->vertexCount = 0;
+ }
+ }
+ } else {
+ cache = new QGL2PEVectorPathCache;
+ cache->vertexCount = 0;
+ data = const_cast<QVectorPath &>(path).addCacheData(q, cache, qopengl2paintengine_cleanup_vectorpath);
+ }
+
+ // Flatten the path at the current scale factor and fill it into the cache struct.
+ if (!cache->vertexCount) {
+ vertexCoordinateArray.clear();
+ vertexCoordinateArray.addPath(path, inverseScale, false);
+ int vertexCount = vertexCoordinateArray.vertexCount();
+ int floatSizeInBytes = vertexCount * 2 * sizeof(float);
+ cache->vertexCount = vertexCount;
+ 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);
+#else
+ cache->vertices = (float *) qMalloc(floatSizeInBytes);
+ memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes);
+#endif
+ }
+
+ prepareForDraw(currentBrush->isOpaque());
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+#ifdef QT_OPENGL_CACHE_AS_VBOS
+ glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0);
+#else
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 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
+ // ### Remove before release...
+ static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty();
+ if (do_vectorpath_cache)
+ path.makeCacheable();
+ vertexCoordinateArray.clear();
+ vertexCoordinateArray.addPath(path, inverseScale, false);
+ prepareForDraw(currentBrush->isOpaque());
+ drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN);
+ }
+
+ } else {
// The path is too complicated & needs the stencil technique
vertexCoordinateArray.clear();
- vertexCoordinateArray.addPath(path, inverseScale);
+ vertexCoordinateArray.addPath(path, inverseScale, false);
fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
- // Stencil the brush onto the dest buffer
- glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0
- glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+ 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);
+ }
- glEnable(GL_STENCIL_TEST);
prepareForDraw(currentBrush->isOpaque());
+
+ if (inRenderText)
+ prepareDepthRangeForRenderText();
+
+ // Stencil the brush onto the dest buffer
composite(vertexCoordinateArray.boundingRect());
- glDisable(GL_STENCIL_TEST);
+
+ if (inRenderText)
+ restoreDepthRangeForRenderText();
glStencilMask(0);
+
+ updateClipScissorTest();
}
}
-void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill)
+void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
+ int count,
+ int *stops,
+ int stopCount,
+ const QGLRect &bounds,
+ StencilFillMode mode)
{
+ Q_ASSERT(count || stops);
+
// qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()");
- glStencilMask(0xFFFF); // Enable stencil writes
+ glStencilMask(0xff); // Enable stencil writes
- if (stencilBufferDirty) {
- // Clear the stencil buffer to zeros
- glDisable(GL_STENCIL_TEST);
+ if (dirtyStencilRegion.intersects(currentScissorBounds)) {
+ QVector<QRect> clearRegion = dirtyStencilRegion.intersected(currentScissorBounds).rects();
glClearStencil(0); // Clear to zero
- glClear(GL_STENCIL_BUFFER_BIT);
- stencilBufferDirty = false;
+ 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
- glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test
+ useSimpleShader();
+ glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
+
+#ifndef QT_OPENGL_ES_2
+ if (inRenderText) {
+ glPushAttrib(GL_ENABLE_BIT);
+ glDisable(GL_DEPTH_TEST);
+ }
+#endif
+
+ 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);
+ }
- // Setup the stencil op:
- if (useWindingFill) {
- glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); // Inc. for front-facing triangle
- glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); //Dec. for back-facing "holes"
- } else
+ // Inc. for front-facing triangle
+ glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP);
+ // Dec. for back-facing "holes"
+ 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
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+#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);
+ }
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+#endif
+ }
+
+ // Enable color writes & disable stencil writes
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+#ifndef QT_OPENGL_ES_2
+ if (inRenderText)
+ glPopAttrib();
+#endif
+
+}
+
+/*
+ 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 QGL2PaintEngineExPrivate::resetClipIfNeeded()
+{
+ if (maxClip != (GL_STENCIL_HIGH_BIT - 1))
+ return;
+
+ Q_Q(QGL2PaintEngineEx);
- // No point in using a fancy gradient shader for writing into the stencil buffer!
useSimpleShader();
+ glEnable(GL_STENCIL_TEST);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
- glDisable(GL_BLEND);
+ QRectF bounds = q->state()->matrix.inverted().mapRect(QRectF(0, 0, width, height));
+ QGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
- // Draw the vertecies into the stencil buffer:
- drawVertexArrays(vertexArray, GL_TRIANGLE_FAN);
+ // 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);
- // Enable color writes & disable stencil writes
+ // 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 QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
{
- if (brushTextureDirty && mode != ImageDrawingMode)
+ if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
updateBrushTexture();
if (compositionModeDirty)
@@ -883,16 +1174,22 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
glEnable(GL_BLEND);
}
- bool useGlobalOpacityUniform = stateHasOpacity;
- if (stateHasOpacity && (mode != ImageDrawingMode)) {
- // Using a brush
- bool brushIsPattern = (currentBrush->style() >= Qt::Dense1Pattern) &&
- (currentBrush->style() <= Qt::DiagCrossPattern);
-
- if ((currentBrush->style() == Qt::SolidPattern) || brushIsPattern)
- useGlobalOpacityUniform = false; // Global opacity handled by srcPixel shader
+ QGLEngineShaderManager::OpacityMode opacityMode;
+ if (mode == ImageArrayDrawingMode) {
+ opacityMode = QGLEngineShaderManager::AttributeOpacity;
+ } else {
+ opacityMode = stateHasOpacity ? QGLEngineShaderManager::UniformOpacity
+ : QGLEngineShaderManager::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 = QGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader
+ }
}
- shaderManager->setUseGlobalOpacity(useGlobalOpacityUniform);
+ shaderManager->setOpacityMode(opacityMode);
bool changed = shaderManager->useCorrectShaderProg();
// If the shader program needs changing, we change it and mark all uniforms as dirty
@@ -900,11 +1197,10 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
// The shader program has changed so mark all uniforms as dirty:
brushUniformsDirty = true;
shaderMatrixUniformDirty = true;
- depthUniformDirty = true;
opacityUniformDirty = true;
}
- if (brushUniformsDirty && mode != ImageDrawingMode)
+ if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
updateBrushUniforms();
if (shaderMatrixUniformDirty) {
@@ -912,12 +1208,7 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
shaderMatrixUniformDirty = false;
}
- if (depthUniformDirty) {
- shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Depth), (GLfloat)q->state()->currentDepth);
- depthUniformDirty = false;
- }
-
- if (useGlobalOpacityUniform && opacityUniformDirty) {
+ if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
opacityUniformDirty = false;
}
@@ -944,14 +1235,16 @@ void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect)
}
// Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
-void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive)
+void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount,
+ GLenum primitive)
{
// Now setup the pointer to the vertex array:
glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray.data());
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
int previousStop = 0;
- foreach(int stop, vertexArray.stops()) {
+ for (int i=0; i<stopCount; ++i) {
+ int stop = stops[i];
/*
qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1);
for (int i=previousStop; i<stop; ++i)
@@ -963,9 +1256,29 @@ void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray,
glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
}
+void QGL2PaintEngineExPrivate::prepareDepthRangeForRenderText()
+{
+#ifndef QT_OPENGL_ES_2
+ // Get the z translation value from the model view matrix and
+ // transform it using the ortogonal projection with z-near = 0,
+ // and z-far = 1, which is used in QGLWidget::renderText()
+ GLdouble model[4][4];
+ glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
+ float deviceZ = -2 * model[3][2] - 1;
+ glGetFloatv(GL_DEPTH_RANGE, depthRange);
+ float windowZ = depthRange[0] + (deviceZ + 1) * 0.5 * (depthRange[1] - depthRange[0]);
+ glDepthRange(windowZ, windowZ);
+#endif
+}
+void QGL2PaintEngineExPrivate::restoreDepthRangeForRenderText()
+{
+#ifndef QT_OPENGL_ES_2
+ glDepthRange(depthRange[0], depthRange[1]);
+#endif
+}
/////////////////////////////////// Public Methods //////////////////////////////////////////
@@ -982,65 +1295,145 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
{
Q_D(QGL2PaintEngineEx);
- if (brush.style() == Qt::NoBrush)
+ Qt::BrushStyle style = qbrush_style(brush);
+ if (style == Qt::NoBrush)
return;
+ if (!d->inRenderText)
+ ensureActive();
+
+ QOpenGL2PaintEngineState *s = state();
+ bool doOffset = !(s->renderHints & QPainter::Antialiasing) &&
+ (style == Qt::SolidPattern) &&
+ !d->multisamplingAlwaysEnabled;
+
+ if (doOffset) {
+ d->temporaryTransform = s->matrix;
+ QTransform tx = QTransform::fromTranslate(.49, .49);
+ s->matrix = s->matrix * tx;
+ d->matrixDirty = true;
+ }
- ensureActive();
d->setBrush(&brush);
d->fill(path);
- d->setBrush(&(state()->brush)); // reset back to the state's brush
+
+ if (doOffset) {
+ s->matrix = d->temporaryTransform;
+ d->matrixDirty = true;
+ }
}
+extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
+
+
void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
{
Q_D(QGL2PaintEngineEx);
- if (pen.style() == Qt::NoPen)
+ Qt::PenStyle penStyle = qpen_style(pen);
+ const QBrush &penBrush = qpen_brush(pen);
+ if (penStyle == 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();
- if ( (pen.isCosmetic() && (pen.style() == Qt::SolidLine)) && (pen.widthF() < 2.5f) )
- {
- // We only handle solid, cosmetic pens with a width of 1 pixel
- const QBrush& brush = pen.brush();
- d->setBrush(&brush);
+ bool doOffset = !(s->renderHints & QPainter::Antialiasing) && !d->multisamplingAlwaysEnabled;
+ if (doOffset) {
+ d->temporaryTransform = s->matrix;
+ QTransform tx = QTransform::fromTranslate(0.49, .49);
+ s->matrix = s->matrix * tx;
+ d->matrixDirty = true;
+ }
- if (pen.widthF() < 0.01f)
- glLineWidth(1.0);
- else
- glLineWidth(pen.widthF());
+ bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
+ d->setBrush(&penBrush);
+ d->transferMode(BrushDrawingMode);
- d->drawOutline(path);
- d->setBrush(&(state()->brush));
- } else
- return QPaintEngineEx::stroke(path, pen);
-}
+ // 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.
+ d->updateMatrix();
-void QGL2PaintEngineEx::penChanged()
-{
-// qDebug("QGL2PaintEngineEx::penChanged() not implemented!");
-}
+ if (penStyle == Qt::SolidLine) {
+ d->stroker.process(path, pen);
+ } else { // Some sort of dash
+ d->dasher.process(path, pen);
-void QGL2PaintEngineEx::brushChanged()
-{
-// qDebug("QGL2PaintEngineEx::brushChanged()");
- Q_D(QGL2PaintEngineEx);
- d->setBrush(&(state()->brush));
-}
+ QVectorPath dashStroke(d->dasher.points(),
+ d->dasher.elementCount(),
+ d->dasher.elementTypes());
+ d->stroker.process(dashStroke, pen);
+ }
-void QGL2PaintEngineEx::brushOriginChanged()
-{
-// qDebug("QGL2PaintEngineEx::brushOriginChanged()");
- Q_D(QGL2PaintEngineEx);
- d->brushUniformsDirty = true;
+
+ QGLContext *ctx = d->ctx;
+ Q_UNUSED(ctx);
+
+ if (opaque) {
+ d->prepareForDraw(opaque);
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, d->stroker.vertices());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, d->stroker.vertexCount() / 2);
+
+// QBrush b(Qt::green);
+// d->setBrush(&b);
+// d->prepareForDraw(true);
+// glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
+
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+
+ } 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 * d->inverseScale;
+
+ QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra);
+
+ d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2,
+ 0, 0, bounds, QGL2PaintEngineExPrivate::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);
+ d->prepareForDraw(false);
+
+ // Stencil the brush onto the dest buffer
+ d->composite(bounds);
+
+ glStencilMask(0);
+
+ d->updateClipScissorTest();
+ }
+
+ if (doOffset) {
+ s->matrix = d->temporaryTransform;
+ d->matrixDirty = true;
+ }
}
+void QGL2PaintEngineEx::penChanged() { }
+void QGL2PaintEngineEx::brushChanged() { }
+void QGL2PaintEngineEx::brushOriginChanged() { }
+
void QGL2PaintEngineEx::opacityChanged()
{
// qDebug("QGL2PaintEngineEx::opacityChanged()");
Q_D(QGL2PaintEngineEx);
+ state()->opacityChanged = true;
Q_ASSERT(d->shaderManager);
d->brushUniformsDirty = true;
@@ -1051,11 +1444,14 @@ void QGL2PaintEngineEx::compositionModeChanged()
{
// qDebug("QGL2PaintEngineEx::compositionModeChanged()");
Q_D(QGL2PaintEngineEx);
+ state()->compositionModeChanged = true;
d->compositionModeDirty = true;
}
void QGL2PaintEngineEx::renderHintsChanged()
{
+ state()->renderHintsChanged = true;
+
#if !defined(QT_OPENGL_ES_2)
if ((state()->renderHints & QPainter::Antialiasing)
|| (state()->renderHints & QPainter::HighQualityAntialiasing))
@@ -1066,6 +1462,7 @@ void QGL2PaintEngineEx::renderHintsChanged()
Q_D(QGL2PaintEngineEx);
d->lastTexture = GLuint(-1);
+ d->brushTextureDirty = true;
// qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!");
}
@@ -1073,6 +1470,7 @@ void QGL2PaintEngineEx::transformChanged()
{
Q_D(QGL2PaintEngineEx);
d->matrixDirty = true;
+ state()->matrixChanged = true;
}
@@ -1084,16 +1482,19 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c
QGLContext *ctx = d->ctx;
glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
- QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true, true);
+ QGLTexture *texture =
+ ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption
+ | QGLContext::CanFlipNativePixmapBindOption);
- GLfloat top = texture->yInverted ? (pixmap.height() - src.top()) : src.top();
- GLfloat bottom = texture->yInverted ? (pixmap.height() - src.bottom()) : src.bottom();
+ GLfloat top = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.top()) : src.top();
+ GLfloat bottom = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.bottom()) : src.bottom();
QGLRect srcRect(src.left(), top, src.right(), bottom);
bool isBitmap = pixmap.isQBitmap();
bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel();
- d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT,
+ d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap);
}
@@ -1107,19 +1508,39 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const
QGLContext *ctx = d->ctx;
glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
- QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
+ QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
GLuint id = texture->id;
- d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT,
+ d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
state()->renderHints & QPainter::SmoothPixmapTransform, id);
d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel());
}
+void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
+{
+ Q_D(QGL2PaintEngineEx);
+ ensureActive();
+ d->transferMode(ImageDrawingMode);
+
+#ifndef QT_OPENGL_ES_2
+ QGLContext *ctx = d->ctx;
+#endif
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ QGLRect 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);
+}
+
void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
{
Q_D(QGL2PaintEngineEx);
- ensureActive();
+ if (!d->inRenderText)
+ ensureActive();
QOpenGL2PaintEngineState *s = state();
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
@@ -1130,18 +1551,34 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem
drawCached = false;
// don't try to cache huge fonts
- if (ti.fontEngine->fontDef.pixelSize * qSqrt(s->matrix.determinant()) >= 64)
+ const qreal pixelSize = ti.fontEngine->fontDef.pixelSize;
+ if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) >= 64 * 64)
drawCached = false;
+ QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
+ ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
+ : d->glyphCacheType;
+
+ if (d->inRenderText)
+ glyphType = QFontEngineGlyphCache::Raster_A8;
+
+ if (glyphType == QFontEngineGlyphCache::Raster_RGBMask
+ && state()->composition_mode != QPainter::CompositionMode_Source
+ && state()->composition_mode != QPainter::CompositionMode_SourceOver)
+ {
+ drawCached = false;
+ }
+
if (drawCached) {
- d->drawCachedGlyphs(p, ti);
+ d->drawCachedGlyphs(p, glyphType, ti);
return;
}
QPaintEngineEx::drawTextItem(p, ti);
}
-void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)
+void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType,
+ const QTextItemInt &ti)
{
Q_Q(QGL2PaintEngineEx);
QOpenGL2PaintEngineState *s = q->state();
@@ -1151,13 +1588,10 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextIte
QTransform matrix = QTransform::fromTranslate(p.x(), p.y());
ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
- QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
- ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
- : QFontEngineGlyphCache::Raster_A8;
-
QGLTextureGlyphCache *cache =
(QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, s->matrix);
- if (!cache) {
+
+ if (!cache || cache->cacheType() != glyphType) {
cache = new QGLTextureGlyphCache(ctx, glyphType, s->matrix);
ti.fontEngine->setGlyphCache(ctx, cache);
}
@@ -1168,15 +1602,10 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextIte
if (cache->width() == 0 || cache->height() == 0)
return;
+ if (inRenderText)
+ transferMode(BrushDrawingMode);
transferMode(TextDrawingMode);
- if (glyphType == QFontEngineGlyphCache::Raster_A8)
- shaderManager->setMaskType(QGLEngineShaderManager::PixelMask);
- else if (glyphType == QFontEngineGlyphCache::Raster_RGBMask)
- shaderManager->setMaskType(QGLEngineShaderManager::SubPixelMask);
- //### TODO: Gamma correction
- shaderManager->setTextureCoordsEnabled(true);
-
int margin = cache->glyphMargin();
GLfloat dx = 1.0 / cache->width();
@@ -1197,111 +1626,268 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextIte
textureCoordinateArray.addRect(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
}
- glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
- glBindTexture(GL_TEXTURE_2D, cache->texture());
- updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
+ if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr)
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
+ if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr)
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
QBrush pensBrush = q->state()->pen.brush();
setBrush(&pensBrush);
- prepareForDraw(false); // Text always causes src pixels to be transparent
+ if (inRenderText)
+ prepareDepthRangeForRenderText();
- shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
+ if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
- if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr)
- glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
- if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr)
- glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
+ // Subpixel antialiasing without gamma correction
+
+ QPainter::CompositionMode compMode = q->state()->composition_mode;
+ Q_ASSERT(compMode == QPainter::CompositionMode_Source
+ || compMode == QPainter::CompositionMode_SourceOver);
+
+ shaderManager->setMaskType(QGLEngineShaderManager::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);
+
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
+ glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
+
+ shaderManager->setMaskType(QGLEngineShaderManager::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(QGLEngineShaderManager::PixelMask);
+ prepareForDraw(false); // Text always causes src pixels to be transparent
+ }
+ //### TODO: Gamma correction
+
+ glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, cache->texture());
+ updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
+
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
- setBrush(&(q->state()->brush)); //###
+ if (inRenderText)
+ restoreDepthRangeForRenderText();
}
-bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
+void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
{
+ // Use fallback for extended composition modes.
+ if (state()->composition_mode > QPainter::CompositionMode_Plus) {
+ QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints);
+ return;
+ }
+
Q_D(QGL2PaintEngineEx);
-// qDebug("QGL2PaintEngineEx::begin()");
- d->drawable.setDevice(pdev);
- d->ctx = d->drawable.context();
-
- if (d->ctx->d_ptr->active_engine) {
- QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(d->ctx->d_ptr->active_engine);
- QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr);
- p->transferMode(BrushDrawingMode);
- p->drawable.doneCurrent();
+ GLfloat dx = 1.0f / pixmap.size().width();
+ GLfloat dy = 1.0f / pixmap.size().height();
+
+ d->vertexCoordinateArray.clear();
+ d->textureCoordinateArray.clear();
+ d->opacityArray.reset();
+
+ bool allOpaque = true;
+
+ for (int i = 0; i < dataCount; ++i) {
+ qreal s = 0;
+ qreal c = 1;
+ if (drawingData[i].rotation != 0) {
+ s = qFastSin(drawingData[i].rotation * Q_PI / 180);
+ c = qFastCos(drawingData[i].rotation * Q_PI / 180);
+ }
+
+ qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width();
+ qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height();
+ QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c);
+ QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c);
+
+ d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
+ d->vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y());
+ d->vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
+ d->vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y());
+ d->vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y());
+ d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y());
+
+ QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy,
+ drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy);
+
+ d->textureCoordinateArray.lineToArray(src.right, src.bottom);
+ d->textureCoordinateArray.lineToArray(src.right, src.top);
+ d->textureCoordinateArray.lineToArray(src.left, src.top);
+ d->textureCoordinateArray.lineToArray(src.left, src.top);
+ d->textureCoordinateArray.lineToArray(src.left, src.bottom);
+ d->textureCoordinateArray.lineToArray(src.right, src.bottom);
+
+ qreal opacity = drawingData[i].opacity * state()->opacity;
+ d->opacityArray << opacity << opacity << opacity << opacity << opacity << opacity;
+ allOpaque &= (opacity >= 0.99f);
}
- d->ctx->d_ptr->active_engine = this;
- d->last_created_state = 0;
+ ensureActive();
- d->drawable.makeCurrent();
- QSize sz = d->drawable.size();
- d->width = sz.width();
- d->height = sz.height();
- d->mode = BrushDrawingMode;
+ QGLContext *ctx = d->ctx;
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption
+ | QGLContext::CanFlipNativePixmapBindOption);
+
+ if (texture->options & QGLContext::InvertedYBindOption) {
+ // Flip texture y-coordinate.
+ QGLPoint *data = d->textureCoordinateArray.data();
+ for (int i = 0; i < 6 * dataCount; ++i)
+ data[i].y = 1 - data[i].y;
+ }
-#if !defined(QT_OPENGL_ES_2)
- qt_resolve_version_2_0_functions(d->ctx);
-#endif
+ d->transferMode(ImageArrayDrawingMode);
- d->shaderManager = QGLEngineShaderManager::managerForContext(d->ctx);
- d->shaderManager->setDirty();
+ bool isBitmap = pixmap.isQBitmap();
+ bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque;
+
+ d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
+ state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
+
+ // Setup for texture drawing
+ d->shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
+ if (d->prepareForDraw(isOpaque))
+ d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
- glViewport(0, 0, d->width, d->height);
+ if (isBitmap) {
+ QColor col = qt_premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity);
+ d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::PatternColor), col);
+ }
-// glClearColor(0.0, 1.0, 0.0, 1.0);
-// glClear(GL_COLOR_BUFFER_BIT);
-// d->ctx->swapBuffers();
-// qDebug("You should see green now");
-// sleep(5);
+ glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount);
+}
+bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
+{
+ Q_D(QGL2PaintEngineEx);
+
+// qDebug("QGL2PaintEngineEx::begin()");
+ if (pdev->devType() == QInternal::OpenGL)
+ d->device = static_cast<QGLPaintDevice*>(pdev);
+ else
+ d->device = QGLPaintDevice::getDevice(pdev);
+
+ if (!d->device)
+ return false;
+
+ d->ctx = d->device->context();
+ d->ctx->d_ptr->active_engine = this;
+
+ const QSize sz = d->device->size();
+ d->width = sz.width();
+ d->height = sz.height();
+ d->mode = BrushDrawingMode;
d->brushTextureDirty = true;
d->brushUniformsDirty = true;
d->matrixDirty = true;
d->compositionModeDirty = true;
- d->stencilBufferDirty = true;
- d->simpleShaderDepthUniformDirty = true;
- d->depthUniformDirty = true;
d->opacityUniformDirty = true;
- d->needsSync = false;
-
+ d->needsSync = true;
d->use_system_clip = !systemClip().isEmpty();
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
- glDepthFunc(GL_LEQUAL);
- glDepthMask(false);
+ 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();
#if !defined(QT_OPENGL_ES_2)
- glDisable(GL_MULTISAMPLE);
+ bool success = qt_resolve_version_2_0_functions(d->ctx)
+ && qt_resolve_buffer_extensions(d->ctx);
+ Q_ASSERT(success);
+ Q_UNUSED(success);
#endif
- QGLPixmapData *source = d->drawable.copyOnBegin();
- if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) {
- if (d->drawable.hasTransparentBackground())
- glClearColor(0.0, 0.0, 0.0, 0.0);
- else {
- const QColor &c = d->drawable.backgroundColor();
- float alpha = c.alphaF();
- glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
- }
- glClear(GL_COLOR_BUFFER_BIT);
- } else if (source) {
- QGLContext *ctx = d->ctx;
+ d->shaderManager = new QGLEngineShaderManager(d->ctx);
+
+ if (!d->inRenderText) {
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ }
- d->transferMode(ImageDrawingMode);
+#if !defined(QT_OPENGL_ES_2)
+ glDisable(GL_MULTISAMPLE);
+#endif
- glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
- source->bind(false);
+ d->glyphCacheType = QFontEngineGlyphCache::Raster_A8;
- QRect rect(0, 0, source->width(), source->height());
- d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
- d->drawTexture(QRectF(rect), QRectF(rect), rect.size(), true);
- }
+#if !defined(QT_OPENGL_ES_2)
+#if defined(Q_WS_WIN)
+ if (qt_cleartype_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().sampleBuffers();
+#else
+ d->multisamplingAlwaysEnabled = false;
+#endif
- d->systemStateChanged();
return true;
}
@@ -1309,19 +1895,11 @@ bool QGL2PaintEngineEx::end()
{
Q_D(QGL2PaintEngineEx);
QGLContext *ctx = d->ctx;
- if (ctx->d_ptr->active_engine != this) {
- QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine);
- if (engine && engine->isActive()) {
- QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr);
- p->transferMode(BrushDrawingMode);
- p->drawable.doneCurrent();
- }
- d->drawable.makeCurrent();
- }
glUseProgram(0);
d->transferMode(BrushDrawingMode);
- d->drawable.swapBuffers();
+ d->device->endPaint();
+
#if defined(Q_WS_X11)
// On some (probably all) drivers, deleting an X pixmap which has been bound to a texture
// before calling glFinish/swapBuffers renders garbage. Presumably this is because X deletes
@@ -1330,9 +1908,20 @@ bool QGL2PaintEngineEx::end()
// them here, after swapBuffers, where they can be safely deleted.
ctx->d_func()->boundPixmaps.clear();
#endif
- d->drawable.doneCurrent();
d->ctx->d_ptr->active_engine = 0;
+ d->resetGLState();
+
+ delete d->shaderManager;
+ d->shaderManager = 0;
+
+#ifdef QT_OPENGL_CACHE_AS_VBOS
+ if (!d->unusedVBOSToClean.isEmpty()) {
+ glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData());
+ d->unusedVBOSToClean.clear();
+ }
+#endif
+
return false;
}
@@ -1342,50 +1931,57 @@ void QGL2PaintEngineEx::ensureActive()
QGLContext *ctx = d->ctx;
if (isActive() && ctx->d_ptr->active_engine != this) {
- QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine);
- if (engine && engine->isActive()) {
- QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr);
- p->transferMode(BrushDrawingMode);
- p->drawable.doneCurrent();
- }
- d->drawable.makeCurrent();
-
ctx->d_ptr->active_engine = this;
-
d->needsSync = true;
}
+ d->device->ensureActiveTarget();
+
if (d->needsSync) {
+ d->transferMode(BrushDrawingMode);
glViewport(0, 0, d->width, d->height);
- glDepthMask(false);
- glDepthFunc(GL_LEQUAL);
- setState(state());
d->needsSync = false;
+ d->shaderManager->setDirty();
+ setState(state());
}
}
-void QGL2PaintEngineExPrivate::updateDepthScissorTest()
+void QGL2PaintEngineExPrivate::updateClipScissorTest()
{
Q_Q(QGL2PaintEngineEx);
- if (q->state()->depthTestEnabled)
- glEnable(GL_DEPTH_TEST);
- else
- glDisable(GL_DEPTH_TEST);
+ 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);
+ }
- if (q->state()->scissorTestEnabled) {
- QRect bounds = q->state()->rectangleClip;
- if (bounds.isNull() || !q->painter()->hasClipping()) {
- if (use_system_clip)
- bounds = systemClip.boundingRect();
- else
- bounds = QRect(0, 0, width, height);
- }
+#ifdef QT_GL_NO_SCISSOR_TEST
+ currentScissorBounds = QRect(0, 0, width, height);
+#else
+ QRect bounds = q->state()->rectangleClip;
+ if (!q->state()->clipEnabled) {
+ if (use_system_clip)
+ bounds = systemClip.boundingRect();
+ else
+ bounds = QRect(0, 0, width, height);
+ } else {
+ if (use_system_clip)
+ 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);
- } else {
- glDisable(GL_SCISSOR_TEST);
}
+#endif
}
void QGL2PaintEngineExPrivate::setScissor(const QRect &rect)
@@ -1402,70 +1998,93 @@ void QGL2PaintEngineEx::clipEnabledChanged()
{
Q_D(QGL2PaintEngineEx);
- d->simpleShaderDepthUniformDirty = true;
- d->depthUniformDirty = true;
+ state()->clipChanged = true;
- if (painter()->hasClipping()) {
- d->regenerateDepthClip();
- } else {
- if (d->use_system_clip) {
- state()->currentDepth = -0.5f;
- } else {
- state()->depthTestEnabled = false;
- }
+ if (painter()->hasClipping())
+ d->regenerateClip();
+ else
+ d->systemStateChanged();
+}
- d->updateDepthScissorTest();
- }
+void QGL2PaintEngineExPrivate::clearClip(uint value)
+{
+ dirtyStencilRegion -= currentScissorBounds;
+
+ glStencilMask(0xff);
+ glClearStencil(value);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glStencilMask(0x0);
+
+ q->state()->needsClipBufferClear = false;
}
-void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, float depth)
+void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value)
{
transferMode(BrushDrawingMode);
if (matrixDirty)
updateMatrix();
- if (q->state()->needsDepthBufferClear) {
- glDepthMask(true);
- glClearDepth(0.5);
- glClear(GL_DEPTH_BUFFER_BIT);
- q->state()->needsDepthBufferClear = false;
- glDepthMask(false);
- }
+ stencilClean = false;
- if (path.isEmpty())
+ 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;
+ }
- glDisable(GL_BLEND);
- glDepthMask(false);
+ 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);
+ vertexCoordinateArray.addPath(path, inverseScale, false);
- glDepthMask(GL_FALSE);
- fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
+ if (!singlePass)
+ fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill());
- // Stencil the clip onto the clip buffer
glColorMask(false, false, false, false);
- glDepthMask(true);
+ glEnable(GL_STENCIL_TEST);
+ useSimpleShader();
- shaderManager->simpleProgram()->setUniformValue("depth", depth);
- simpleShaderDepthUniformDirty = true;
+ 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
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_ALWAYS);
+ 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);
- glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0
- glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+ 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());
+ }
- glEnable(GL_STENCIL_TEST);
- composite(vertexCoordinateArray.boundingRect());
- glDisable(GL_STENCIL_TEST);
+ // 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);
- glDepthMask(false);
}
void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
@@ -1473,100 +2092,95 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
// qDebug("QGL2PaintEngineEx::clip()");
Q_D(QGL2PaintEngineEx);
- if (op == Qt::ReplaceClip && !d->hasClipOperations())
+ state()->clipChanged = true;
+
+ ensureActive();
+
+ if (op == Qt::ReplaceClip) {
op = Qt::IntersectClip;
+ if (d->hasClipOperations()) {
+ d->systemStateChanged();
+ state()->canRestoreClip = false;
+ }
+ }
- if (!path.isEmpty() && op == Qt::IntersectClip && (path.hints() & QVectorPath::RectangleHint)) {
+#ifndef QT_GL_NO_SCISSOR_TEST
+ if (!path.isEmpty() && op == Qt::IntersectClip && (path.shape() == QVectorPath::RectangleHint)) {
const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
QRectF rect(points[0], points[2]);
if (state()->matrix.type() <= QTransform::TxScale) {
- rect = state()->matrix.mapRect(rect);
-
- if ((d->use_system_clip && rect.contains(d->systemClip.boundingRect()))
- || rect.contains(QRect(0, 0, d->width, d->height)))
- return;
-
- if (state()->rectangleClip.isValid()) {
- state()->rectangleClip = state()->rectangleClip.intersected(rect.toRect());
-
- state()->hasRectangleClip = true;
- state()->scissorTestEnabled = true;
-
- glEnable(GL_SCISSOR_TEST);
- d->setScissor(state()->rectangleClip);
-
- return;
- }
+ state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect());
+ d->updateClipScissorTest();
+ return;
}
}
+#endif
- if (!state()->hasRectangleClip)
- state()->rectangleClip = QRect();
-
- if (state()->rectangleClip.isValid() && op != Qt::NoClip && op != Qt::ReplaceClip) {
- QPainterPath path;
- path.addRect(state()->rectangleClip);
-
- state()->rectangleClip = QRect();
- d->updateDepthScissorTest();
-
- glDepthFunc(GL_ALWAYS);
-
- state()->maxDepth = 0.5f;
- d->writeClip(qtVectorPathForPath(path), state()->maxDepth);
- state()->currentDepth = 0.25f;
- state()->depthTestEnabled = true;
-
- glDepthFunc(GL_LEQUAL);
- glEnable(GL_DEPTH_TEST);
- }
+ const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect();
switch (op) {
case Qt::NoClip:
if (d->use_system_clip) {
- glEnable(GL_DEPTH_TEST);
- state()->depthTestEnabled = true;
- state()->currentDepth = -0.5;
+ state()->clipTestEnabled = true;
+ state()->currentClip = 1;
} else {
- glDisable(GL_DEPTH_TEST);
- state()->depthTestEnabled = false;
+ state()->clipTestEnabled = false;
}
+ state()->rectangleClip = QRect(0, 0, d->width, d->height);
state()->canRestoreClip = false;
+ d->updateClipScissorTest();
break;
case Qt::IntersectClip:
- state()->maxDepth = (1.0f + state()->maxDepth) * 0.5;
- d->writeClip(path, state()->maxDepth);
- state()->currentDepth = 1.5 * state()->maxDepth - 0.5f;
- state()->depthTestEnabled = true;
+ 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;
- case Qt::ReplaceClip:
- d->systemStateChanged();
- state()->rectangleClip = QRect();
- state()->maxDepth = 0.5f;
- glDepthFunc(GL_ALWAYS);
- d->writeClip(path, state()->maxDepth);
- state()->currentDepth = 0.25f;
+ case Qt::UniteClip: {
+ d->resetClipIfNeeded();
+ ++d->maxClip;
+ if (state()->rectangleClip.isValid()) {
+ QPainterPath path;
+ path.addRect(state()->rectangleClip);
+
+ // flush the existing clip rectangle to the depth buffer
+ d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(path)), d->maxClip);
+ }
+
+ state()->clipTestEnabled = false;
+#ifndef QT_GL_NO_SCISSOR_TEST
+ QRect oldRectangleClip = state()->rectangleClip;
+
+ state()->rectangleClip = state()->rectangleClip.united(pathRect);
+ d->updateClipScissorTest();
+
+ QRegion extendRegion = QRegion(state()->rectangleClip) - oldRectangleClip;
+
+ if (!extendRegion.isEmpty()) {
+ QPainterPath extendPath;
+ extendPath.addRegion(extendRegion);
+
+ // first clear the depth buffer in the extended region
+ d->writeClip(qtVectorPathForPath(state()->matrix.inverted().map(extendPath)), 0);
+ }
+#endif
+ // now write the clip path
+ d->writeClip(path, d->maxClip);
state()->canRestoreClip = false;
- state()->depthTestEnabled = true;
+ state()->currentClip = d->maxClip;
+ state()->clipTestEnabled = true;
break;
- case Qt::UniteClip:
- glDepthFunc(GL_ALWAYS);
- d->writeClip(path, state()->maxDepth);
- state()->canRestoreClip = false;
- state()->depthTestEnabled = true;
+ }
+ default:
break;
}
-
- glDepthFunc(GL_LEQUAL);
- if (state()->depthTestEnabled) {
- glEnable(GL_DEPTH_TEST);
- d->simpleShaderDepthUniformDirty = true;
- d->depthUniformDirty = true;
- }
}
-void QGL2PaintEngineExPrivate::regenerateDepthClip()
+void QGL2PaintEngineExPrivate::regenerateClip()
{
systemStateChanged();
replayClipOperations();
@@ -1575,65 +2189,48 @@ void QGL2PaintEngineExPrivate::regenerateDepthClip()
void QGL2PaintEngineExPrivate::systemStateChanged()
{
Q_Q(QGL2PaintEngineEx);
- use_system_clip = !systemClip.isEmpty();
- glDisable(GL_DEPTH_TEST);
- q->state()->depthTestEnabled = false;
- q->state()->scissorTestEnabled = false;
- q->state()->needsDepthBufferClear = true;
- q->state()->hasRectangleClip = false;
-
- glDisable(GL_SCISSOR_TEST);
-
- q->state()->currentDepth = -0.5f;
- q->state()->maxDepth = 0.5f;
-
- q->state()->rectangleClip = QRect(0, 0, width, height);
-
- if (use_system_clip) {
- if (systemClip.numRects() == 1) {
- QRect bounds = systemClip.boundingRect();
- if (bounds == QRect(0, 0, width, height)) {
- use_system_clip = false;
- return;
- }
+ q->state()->clipChanged = true;
- q->state()->rectangleClip = bounds;
- q->state()->scissorTestEnabled = true;
- updateDepthScissorTest();
+ if (systemClip.isEmpty()) {
+ use_system_clip = false;
+ } else {
+ if (q->paintDevice()->devType() == QInternal::Widget && currentClipWidget) {
+ QWidgetPrivate *widgetPrivate = qt_widget_private(currentClipWidget->window());
+ use_system_clip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter;
} else {
- q->state()->rectangleClip = QRect();
- q->state()->scissorTestEnabled = true;
- updateDepthScissorTest();
-
- QTransform transform = q->state()->matrix;
- q->state()->matrix = QTransform();
- q->transformChanged();
-
- q->state()->needsDepthBufferClear = false;
+ use_system_clip = true;
+ }
+ }
- glDepthMask(true);
+ q->state()->clipTestEnabled = false;
+ q->state()->needsClipBufferClear = true;
- glClearDepth(0);
- glClear(GL_DEPTH_BUFFER_BIT);
+ q->state()->currentClip = 1;
+ maxClip = 1;
- QPainterPath path;
- path.addRegion(systemClip);
+ q->state()->rectangleClip = use_system_clip ? systemClip.boundingRect() : QRect(0, 0, width, height);
+ updateClipScissorTest();
- glDepthFunc(GL_ALWAYS);
- writeClip(qtVectorPathForPath(path), 0.0f);
- glDepthFunc(GL_LEQUAL);
+ if (systemClip.rectCount() == 1) {
+ if (systemClip.boundingRect() == QRect(0, 0, width, height))
+ use_system_clip = false;
+#ifndef QT_GL_NO_SCISSOR_TEST
+ // scissoring takes care of the system clip
+ return;
+#endif
+ }
- glEnable(GL_DEPTH_TEST);
- q->state()->depthTestEnabled = true;
+ if (use_system_clip) {
+ clearClip(0);
- q->state()->matrix = transform;
- q->transformChanged();
- }
+ QPainterPath path;
+ path.addRegion(systemClip);
- q->state()->currentDepth = -0.5f;
- simpleShaderDepthUniformDirty = true;
- depthUniformDirty = true;
+ q->state()->currentClip = 0;
+ writeClip(qtVectorPathForPath(q->state()->matrix.inverted().map(path)), 1);
+ q->state()->currentClip = 1;
+ q->state()->clipTestEnabled = true;
}
}
@@ -1648,38 +2245,45 @@ void QGL2PaintEngineEx::setState(QPainterState *new_state)
QPaintEngineEx::setState(s);
- if (s == d->last_created_state) {
- d->last_created_state = 0;
+ 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;
}
- renderHintsChanged();
+ // Setting the state as part of a restore().
- d->matrixDirty = true;
- d->compositionModeDirty = true;
- d->brushTextureDirty = true;
- d->brushUniformsDirty = true;
- d->simpleShaderDepthUniformDirty = true;
- d->depthUniformDirty = true;
- d->simpleShaderMatrixUniformDirty = true;
- d->shaderMatrixUniformDirty = true;
- d->opacityUniformDirty = true;
+ if (old_state == s || old_state->renderHintsChanged)
+ renderHintsChanged();
- d->shaderManager->setDirty();
+ if (old_state == s || old_state->matrixChanged) {
+ d->matrixDirty = true;
+ d->simpleShaderMatrixUniformDirty = true;
+ d->shaderMatrixUniformDirty = true;
+ }
- if (old_state && old_state != s && old_state->canRestoreClip) {
- d->updateDepthScissorTest();
- glDepthMask(false);
- glDepthFunc(GL_LEQUAL);
- s->maxDepth = old_state->maxDepth;
- } else {
- d->regenerateDepthClip();
+ 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 *QGL2PaintEngineEx::createState(QPainterState *orig) const
{
- Q_D(const QGL2PaintEngineEx);
+ if (orig)
+ const_cast<QGL2PaintEngineEx *>(this)->ensureActive();
QOpenGL2PaintEngineState *s;
if (!orig)
@@ -1687,32 +2291,38 @@ QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const
else
s = new QOpenGL2PaintEngineState(*static_cast<QOpenGL2PaintEngineState *>(orig));
- d->last_created_state = s;
+ s->matrixChanged = false;
+ s->compositionModeChanged = false;
+ s->opacityChanged = false;
+ s->renderHintsChanged = false;
+ s->clipChanged = false;
+
return s;
}
+void QGL2PaintEngineEx::setRenderTextActive(bool active)
+{
+ Q_D(QGL2PaintEngineEx);
+ d->inRenderText = active;
+}
+
QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other)
: QPainterState(other)
{
- needsDepthBufferClear = other.needsDepthBufferClear;
- depthTestEnabled = other.depthTestEnabled;
- scissorTestEnabled = other.scissorTestEnabled;
- currentDepth = other.currentDepth;
- maxDepth = other.maxDepth;
+ isNew = true;
+ needsClipBufferClear = other.needsClipBufferClear;
+ clipTestEnabled = other.clipTestEnabled;
+ currentClip = other.currentClip;
canRestoreClip = other.canRestoreClip;
rectangleClip = other.rectangleClip;
- hasRectangleClip = other.hasRectangleClip;
}
QOpenGL2PaintEngineState::QOpenGL2PaintEngineState()
{
- needsDepthBufferClear = true;
- depthTestEnabled = false;
- scissorTestEnabled = false;
- currentDepth = -0.5f;
- maxDepth = 0.5f;
+ isNew = true;
+ needsClipBufferClear = true;
+ clipTestEnabled = false;
canRestoreClip = true;
- hasRectangleClip = false;
}
QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index fa216bc49..00844765a 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -58,11 +58,17 @@
#include <private/qpaintengineex_p.h>
#include <private/qglengineshadermanager_p.h>
#include <private/qgl2pexvertexarray_p.h>
+#include <private/qglpaintdevice_p.h>
+#include <private/qglpixmapfilter_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qdatabuffer_p.h>
+#include <private/qtriangulatingstroker_p.h>
enum EngineMode {
ImageDrawingMode,
TextDrawingMode,
- BrushDrawingMode
+ BrushDrawingMode,
+ ImageArrayDrawingMode
};
QT_BEGIN_NAMESPACE
@@ -77,21 +83,21 @@ public:
QOpenGL2PaintEngineState();
~QOpenGL2PaintEngineState();
- bool needsDepthBufferClear;
- qreal depthBufferClearValue;
-
- bool depthTestEnabled;
- bool scissorTestEnabled;
- qreal currentDepth;
- qreal maxDepth;
+ 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;
- bool canRestoreClip;
QRect rectangleClip;
- bool hasRectangleClip;
};
-
-class QGL2PaintEngineEx : public QPaintEngineEx
+class Q_OPENGL_EXPORT QGL2PaintEngineEx : public QPaintEngineEx
{
Q_DECLARE_PRIVATE(QGL2PaintEngineEx)
public:
@@ -118,12 +124,15 @@ public:
virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
-
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
Qt::ImageConversionFlags flags = Qt::AutoColor);
+ virtual void drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr);
+
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
- Type type() const { return OpenGL; }
+ virtual void drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints);
+
+ Type type() const { return OpenGL2; }
void setState(QPainterState *s);
QPainterState *createState(QPainterState *orig) const;
@@ -133,23 +142,39 @@ public:
inline const QOpenGL2PaintEngineState *state() const {
return static_cast<const QOpenGL2PaintEngineState *>(QPaintEngineEx::state());
}
- virtual void sync();
+
+ void beginNativePainting();
+ void endNativePainting();
+
+ const QGLContext* context();
+
+ QPixmapFilter *pixmapFilter(int type, const QPixmapFilter *prototype);
+
+ void setRenderTextActive(bool);
private:
Q_DISABLE_COPY(QGL2PaintEngineEx)
};
+
class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate
{
Q_DECLARE_PUBLIC(QGL2PaintEngineEx)
public:
+ enum StencilFillMode {
+ OddEvenFillMode,
+ WindingFillMode,
+ TriStripStrokeFillMode
+ };
+
QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) :
q(q_ptr),
width(0), height(0),
ctx(0),
- currentBrush( &(q->state()->brush) ),
+ currentBrush(0),
inverseScale(1),
- shaderManager(0)
+ shaderManager(0),
+ inRenderText(false)
{ }
~QGL2PaintEngineExPrivate();
@@ -163,33 +188,47 @@ public:
void setBrush(const QBrush* brush);
void transferMode(EngineMode newMode);
+ void resetGLState();
// fill, drawOutline, drawTexture & drawCachedGlyphs are the rendering entry points:
void fill(const QVectorPath &path);
- void drawOutline(const QVectorPath& path);
void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false);
- void drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti);
+ void drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, const QTextItemInt &ti);
+
+ void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive);
+ void drawVertexArrays(QGL2PEXVertexArray &vertexArray, GLenum primitive) {
+ drawVertexArrays((const float *) vertexArray.data(), vertexArray.stops(), vertexArray.stopCount(), primitive);
+ }
- void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive);
// ^ draws whatever is in the vertex array
void composite(const QGLRect& boundingRect);
// ^ Composites the bounding rect onto dest buffer
- void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill);
+
+ void fillStencilWithVertexArray(const float *data, int count, int *stops, int stopCount, const QGLRect &bounds, StencilFillMode mode);
+ void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) {
+ fillStencilWithVertexArray((const float *) vertexArray.data(), 0, vertexArray.stops(), vertexArray.stopCount(),
+ vertexArray.boundingRect(),
+ useWindingFill ? WindingFillMode : OddEvenFillMode);
+ }
// ^ Calls drawVertexArrays to render into stencil buffer
bool prepareForDraw(bool srcPixelsAreOpaque);
// ^ returns whether the current program changed or not
inline void useSimpleShader();
- inline QColor premultiplyColor(QColor c, GLfloat opacity);
+
+ void prepareDepthRangeForRenderText();
+ void restoreDepthRangeForRenderText();
+
+ static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; }
+ static QGL2PaintEngineExPrivate *getData(QGL2PaintEngineEx *engine) { return engine->d_func(); }
QGL2PaintEngineEx* q;
- QGLDrawable drawable;
+ QGLPaintDevice* device;
int width, height;
QGLContext *ctx;
EngineMode mode;
-
- mutable QOpenGL2PaintEngineState *last_created_state;
+ QFontEngineGlyphCache::Type glyphCacheType;
// Dirty flags
bool matrixDirty; // Implies matrix uniforms are also dirty
@@ -198,17 +237,20 @@ public:
bool brushUniformsDirty;
bool simpleShaderMatrixUniformDirty;
bool shaderMatrixUniformDirty;
- bool stencilBufferDirty;
- bool depthUniformDirty;
- bool simpleShaderDepthUniformDirty;
bool opacityUniformDirty;
+ bool stencilClean; // Has the stencil not been used for clipping so far?
+ QRegion dirtyStencilRegion;
+ QRect currentScissorBounds;
+ uint maxClip;
+
const QBrush* currentBrush; // May not be the state's brush!
GLfloat inverseScale;
QGL2PEXVertexArray vertexCoordinateArray;
QGL2PEXVertexArray textureCoordinateArray;
+ QDataBuffer<GLfloat> opacityArray;
GLfloat staticVertexCoordinateArray[8];
GLfloat staticTextureCoordinateArray[8];
@@ -217,10 +259,13 @@ public:
QGLEngineShaderManager* shaderManager;
- void writeClip(const QVectorPath &path, float depth);
- void updateDepthScissorTest();
+ void clearClip(uint value);
+ void writeClip(const QVectorPath &path, uint value);
+ void resetClipIfNeeded();
+
+ void updateClipScissorTest();
void setScissor(const QRect &rect);
- void regenerateDepthClip();
+ void regenerateClip();
void systemStateChanged();
uint use_system_clip : 1;
@@ -232,6 +277,27 @@ public:
GLuint lastTexture;
bool needsSync;
+ bool inRenderText;
+ bool multisamplingAlwaysEnabled;
+
+ GLfloat depthRange[2];
+
+ float textureInvertedY;
+
+ QTriangulatingStroker stroker;
+ QDashedStrokeProcessor dasher;
+ QTransform temporaryTransform;
+
+ QScopedPointer<QPixmapFilter> convolutionFilter;
+ QScopedPointer<QPixmapFilter> colorizeFilter;
+ QScopedPointer<QPixmapFilter> blurFilter;
+ QScopedPointer<QPixmapFilter> animationBlurFilter;
+ QScopedPointer<QPixmapFilter> fastBlurFilter;
+ QScopedPointer<QPixmapFilter> dropShadowFilter;
+ QScopedPointer<QPixmapFilter> fastDropShadowFilter;
+
+ QSet<QVectorPath::CacheEntry *> pathCaches;
+ QVector<GLuint> unusedVBOSToClean;
};
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp
new file mode 100644
index 000000000..6082f49d8
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp
@@ -0,0 +1,549 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtriangulatingstroker_p.h"
+#include <qmath.h>
+
+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();
+ m_vertices.add(m_vertices.at(count-2));
+ m_vertices.add(m_vertices.at(count-1));
+}
+
+
+void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen)
+{
+ 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<t<1], we
+ // will get longer segments where the curvature is small and smaller
+ // segments when the curvature is high.
+ //
+ // To get a rough idea of the length of each curve, I pretend that
+ // the curve is a 90 degree arc, whose radius is
+ // qMax(curveBounds.width, curveBounds.height). Based on this
+ // logic we can estimate the length of the outline edges based on
+ // the radius + a pen width and adjusting for scale factors
+ // depending on if the pen is cosmetic or not.
+ //
+ // The curvyness value of PI/14 was based on,
+ // arcLength=2*PI*r/4=PI/2 and splitting length into somewhere
+ // between 3 and 8 where 5 seemed to be give pretty good results
+ // hence: Q_PI/14. Lower divisors will give more detail at the
+ // direct cost of performance.
+
+ // simplfy pens that are thin in device size (2px wide or less)
+ if (realWidth < 2.5 && (cosmetic || m_inv_scale == 1)) {
+ if (m_cap_style == Qt::RoundCap)
+ m_cap_style = Qt::SquareCap;
+ if (m_join_style == Qt::RoundJoin)
+ m_join_style = Qt::MiterJoin;
+ m_curvyness_add = 0.5;
+ m_curvyness_mul = CURVE_FLATNESS / m_inv_scale;
+ m_roundness = 1;
+ } else if (cosmetic) {
+ m_curvyness_add = realWidth / 2;
+ m_curvyness_mul = CURVE_FLATNESS;
+ m_roundness = qMax<int>(4, realWidth * CURVE_FLATNESS);
+ } else {
+ m_curvyness_add = m_width;
+ m_curvyness_mul = CURVE_FLATNESS / m_inv_scale;
+ m_roundness = qMax<int>(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;
+
+ Qt::PenCapStyle cap = m_cap_style;
+
+ if (!types) {
+ 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) {
+ join(pts);
+ lineTo(pts);
+ pts += 2;
+ }
+
+ endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);
+
+ } else {
+ bool endsAtStart;
+ 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<end && types[i] != QPainterPath::MoveToElement) {
+ ++i;
+ }
+ endsAtStart = startPts[0] == pts[i*2 - 2] && startPts[1] == pts[i*2 - 1];
+ if (endsAtStart || path.hasImplicitClose())
+ m_cap_style = Qt::FlatCap;
+
+ moveTo(pts);
+ m_cap_style = cap;
+ pts+=2;
+ ++types;
+ break; }
+ case QPainterPath::LineToElement:
+ if (*(types - 1) != QPainterPath::MoveToElement)
+ join(pts);
+ lineTo(pts);
+ pts+=2;
+ ++types;
+ break;
+ case QPainterPath::CurveToElement:
+ if (*(types - 1) != QPainterPath::MoveToElement)
+ join(pts);
+ cubicTo(pts);
+ pts+=6;
+ types+=3;
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+ }
+
+ endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);
+ }
+}
+
+void QTriangulatingStroker::moveTo(const qreal *pts)
+{
+ m_cx = pts[0];
+ m_cy = pts[1];
+
+ float x2 = pts[2];
+ float y2 = pts[3];
+ normalVector(m_cx, m_cy, x2, y2, &m_nvx, &m_nvy);
+
+
+ // To acheive jumps we insert zero-area tringles. This is done by
+ // adding two identical points in both the end of previous strip
+ // and beginning of next strip
+ bool invisibleJump = m_vertices.size();
+
+ switch (m_cap_style) {
+ case Qt::FlatCap:
+ if (invisibleJump) {
+ m_vertices.add(m_cx + m_nvx);
+ m_vertices.add(m_cy + m_nvy);
+ }
+ break;
+ case Qt::SquareCap: {
+ float sx = m_cx - m_nvy;
+ float sy = m_cy + m_nvx;
+ if (invisibleJump) {
+ m_vertices.add(sx + m_nvx);
+ m_vertices.add(sy + m_nvy);
+ }
+ emitLineSegment(sx, sy, m_nvx, m_nvy);
+ break; }
+ case Qt::RoundCap: {
+ QVarLengthArray<float> 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<float>(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<threshold; ++i) {
+ qreal t = qreal(i) / threshold_minus_1;
+ QPointF p = bezier.pointAt(t);
+ x = p.x();
+ y = p.y();
+
+ normalVector(cx, cy, x, y, &vx, &vy);
+
+ emitLineSegment(x, y, vx, vy);
+
+ cx = x;
+ cy = y;
+ }
+
+ m_cx = cx;
+ m_cy = cy;
+
+ m_nvx = vx;
+ m_nvy = vy;
+}
+
+void QTriangulatingStroker::join(const qreal *pts)
+{
+ // Creates a join to the next segment (m_cx, m_cy) -> (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<float> 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<float> 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<float> &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_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 qreal *pts = path.points();
+ const QPainterPath::ElementType *types = path.elements();
+ int count = path.elementCount();
+
+ m_points.reset();
+ m_types.reset();
+
+ qreal width = qpen_widthf(pen);
+ if (width == 0)
+ width = 1;
+
+ m_dash_stroker.setDashPattern(pen.dashPattern());
+ m_dash_stroker.setStrokeWidth(pen.isCosmetic() ? width * m_inv_scale : width);
+ m_dash_stroker.setMiterLimit(pen.miterLimit());
+ qreal curvyness = sqrt(width) * m_inv_scale / 8;
+
+ 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();
+ int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * curvyness);
+ if (threshold < 4)
+ threshold = 4;
+ qreal threshold_minus_1 = threshold - 1;
+ for (int i=0; i<threshold; ++i) {
+ QPointF pt = b.pointAt(i / threshold_minus_1);
+ m_dash_stroker.lineTo(pt.x(), pt.y());
+ }
+ pts += 6;
+ types += 3;
+ break; }
+ default: break;
+ }
+ }
+ }
+
+ m_dash_stroker.end();
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h b/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h
new file mode 100644
index 000000000..2dba0ce46
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qtriangulatingstroker_p.h
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTRIANGULATINGSTROKER_P_H
+#define QTRIANGULATINGSTROKER_P_H
+
+#include <private/qdatabuffer_p.h>
+#include <qvarlengtharray.h>
+#include <private/qvectorpath_p.h>
+#include <private/qbezier_p.h>
+#include <private/qnumeric_p.h>
+#include <private/qmath_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTriangulatingStroker
+{
+public:
+ void process(const QVectorPath &path, const QPen &pen);
+
+ 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<float> &points);
+ void endCapOrJoinClosed(const qreal *start, const qreal *cur, bool implicitClose, bool endsAtStart);
+
+
+ QDataBuffer<float> 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);
+
+ 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<qreal> m_points;
+ QDataBuffer<QPainterPath::ElementType> 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/opengl/gl2paintengineex/qtriangulator.cpp b/src/opengl/gl2paintengineex/qtriangulator.cpp
new file mode 100644
index 000000000..21d4b2e49
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qtriangulator.cpp
@@ -0,0 +1,2981 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtriangulator_p.h"
+
+#include <QtGui/qdialog.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpainterpath.h>
+#include <QtGui/private/qbezier_p.h>
+#include <QtGui/private/qdatabuffer_p.h>
+#include <QtCore/qbitarray.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qqueue.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qalgorithms.h>
+#include <QtDebug>
+
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define Q_TRIANGULATOR_DEBUG
+
+#define Q_FIXED_POINT_SCALE 32
+
+// Quick sort.
+template <class T, class LessThan>
+static void sort(T *array, int count, LessThan lessThan)
+{
+ // 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 <class T>
+static void sort(T *array, int count)
+{
+ // 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);
+}
+
+//============================================================================//
+// 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 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)
+{
+ // m_upperLeft = point, m_xOffset = 0/1, m_yOffset = 0/1.
+ QIntersectionPoint p = {point, {0, 1}, {0, 1}};
+ return p;
+}
+
+static inline QIntersectionPoint qIntersectionPoint(int x, int y)
+{
+ // m_upperLeft = (x, y), m_xOffset = 0/1, m_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 T>
+class QMaxHeap
+{
+public:
+ 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<T> m_data;
+};
+
+template <class T>
+void QMaxHeap<T>::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 <class T>
+T QMaxHeap<T>::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;
+}
+
+//============================================================================//
+// QRBTree //
+//============================================================================//
+
+template <class T>
+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 verify() 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 <class T>
+inline QRBTree<T>::~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 <class T>
+inline void QRBTree<T>::clear()
+{
+ if (root)
+ delete root;
+ root = 0;
+}
+
+template <class T>
+void QRBTree<T>::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 <class T>
+void QRBTree<T>::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 <class T>
+void QRBTree<T>::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 <class T>
+inline void QRBTree<T>::attachLeft(Node *parent, Node *child)
+{
+ Q_ASSERT(!parent->left);
+ parent->left = child;
+ child->parent = parent;
+ update(child);
+}
+
+template <class T>
+inline void QRBTree<T>::attachRight(Node *parent, Node *child)
+{
+ Q_ASSERT(!parent->right);
+ parent->right = child;
+ child->parent = parent;
+ update(child);
+}
+
+template <class T>
+void QRBTree<T>::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 <class T>
+void QRBTree<T>::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 <class T>
+void QRBTree<T>::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 <class T>
+void QRBTree<T>::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 <class T>
+void QRBTree<T>::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 <class T>
+inline typename QRBTree<T>::Node *QRBTree<T>::front(Node *node) const
+{
+ while (node->left)
+ node = node->left;
+ return node;
+}
+
+template <class T>
+inline typename QRBTree<T>::Node *QRBTree<T>::back(Node *node) const
+{
+ while (node->right)
+ node = node->right;
+ return node;
+}
+
+template <class T>
+typename QRBTree<T>::Node *QRBTree<T>::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 <class T>
+typename QRBTree<T>::Node *QRBTree<T>::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 <class T>
+int QRBTree<T>::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 <class T>
+bool QRBTree<T>::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 <class T>
+inline bool QRBTree<T>::verify() const
+{
+ return checkRedBlackProperty(root) && blackDepth(root) != -1;
+}
+
+template <class T>
+inline void QRBTree<T>::deleteNode(Node *&node)
+{
+ Q_ASSERT(node);
+ detach(node);
+ node->right = freeList;
+ freeList = node;
+ node = 0;
+}
+
+template <class T>
+inline typename QRBTree<T>::Node *QRBTree<T>::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 <class T>
+int QRBTree<T>::order(Node *left, Node *right)
+{
+ Q_ASSERT(left && right);
+ if (left == right)
+ return 0;
+
+ QVector<Node *> leftAncestors;
+ QVector<Node *> 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;
+}
+
+//============================================================================//
+// 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<T>::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<T>::insert", "Hash set full.");
+}
+
+bool QInt64Set::contains(quint64 key) const
+{
+ Q_ASSERT_X(m_array, "QInt64Hash<T>::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<T>::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 T>
+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 <class T>
+bool QRingBuffer<T>::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 <class T>
+inline const T &QRingBuffer<T>::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 <class T>
+inline void QRingBuffer<T>::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 //
+//============================================================================//
+
+class QTriangulator
+{
+public:
+ typedef QVarLengthArray<int, 6> ShortArray;
+
+ //================================//
+ // QTriangulator::ComplexToSimple //
+ //================================//
+ friend class ComplexToSimple;
+ class ComplexToSimple
+ {
+ public:
+ inline ComplexToSimple(QTriangulator *parent) : m_parent(parent) { }
+ 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<int>::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<int>::Node *searchEdgeLeftOf(int edgeIndex) const;
+ QRBTree<int>::Node *searchEdgeLeftOf(int edgeIndex, QRBTree<int>::Node *after) const;
+ QPair<QRBTree<int>::Node *, QRBTree<int>::Node *> bounds(const QPodPoint &point) const;
+ QPair<QRBTree<int>::Node *, QRBTree<int>::Node *> outerBounds(const QPodPoint &point) const;
+ void splitEdgeListRange(QRBTree<int>::Node *leftmost, QRBTree<int>::Node *rightmost, int vertex, const QIntersectionPoint &intersectionPoint);
+ void reorderEdgeListRange(QRBTree<int>::Node *leftmost, QRBTree<int>::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<Edge> m_edges;
+ QRBTree<int> m_edgeList;
+ QDataBuffer<Event> m_events;
+ QDataBuffer<Split> m_splits;
+ QMaxHeap<Intersection> 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) { }
+ void decompose();
+ private:
+ enum VertexType {MergeVertex, EndVertex, RegularVertex, StartVertex, SplitVertex};
+
+ struct Edge
+ {
+ QRBTree<int>::Node *node;
+ int helper, twin, next, previous;
+ quint32 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<int>::Node *searchEdgeLeftOfEdge(int edgeIndex) const;
+ // Returns the rightmost edge left of the given point.
+ QRBTree<int>::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<int> m_edgeList;
+ QDataBuffer<Edge> m_edges;
+ QDataBuffer<int> m_upperVertex;
+ bool m_clockwiseOrder;
+ };
+
+ //====================================//
+ // QTriangulator::MonotoneToTriangles //
+ //====================================//
+ friend class MonotoneToTriangles;
+ class MonotoneToTriangles
+ {
+ public:
+ inline MonotoneToTriangles(QTriangulator *parent) : m_parent(parent) { }
+ void decompose();
+ private:
+ inline quint32 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(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(indices(i)),
+ m_parent->m_vertices.at(indices(j)), m_parent->m_vertices.at(indices(k)));
+ }
+
+ QTriangulator *m_parent;
+ int m_first;
+ int m_length;
+ };
+
+ inline QTriangulator() { }
+
+ // 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.
+ QTriangleSet triangulate();
+ QPolylineSet polyline();
+private:
+ QDataBuffer<QPodPoint> m_vertices;
+ QVector<quint32> m_indices;
+ uint m_hint;
+};
+
+//============================================================================//
+// QTriangulator //
+//============================================================================//
+
+QTriangleSet 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();
+
+ QTriangleSet 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;
+}
+
+QPolylineSet QTriangulator::polyline()
+{
+ QPolylineSet 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;
+}
+
+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] = Q_TRIANGULATE_END_OF_POLYGON;
+}
+
+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(Q_TRIANGULATE_END_OF_POLYGON);
+ // Fall through.
+ case QPainterPath::LineToElement:
+ m_indices.push_back(quint32(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(quint32(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(quint32(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(Q_TRIANGULATE_END_OF_POLYGON);
+}
+
+void QTriangulator::initialize(const QPainterPath &path, const QTransform &matrix, qreal lod)
+{
+ initialize(qtVectorPathForPath(path), matrix, lod);
+}
+
+//============================================================================//
+// QTriangulator::ComplexToSimple //
+//============================================================================//
+
+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(Q_TRIANGULATE_END_OF_POLYGON);
+ }
+}
+
+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) == 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
+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(e1.from);
+ const QPodPoint &u2 = m_parent->m_vertices.at(e1.to);
+ const QPodPoint &v1 = m_parent->m_vertices.at(e2.from);
+ const QPodPoint &v2 = m_parent->m_vertices.at(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 = 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;
+}
+
+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 = qPointDistanceFromLine(upper, l, u);
+ // d < 0: left, d > 0: right, d == 0: on top
+ if (d == 0)
+ d = qPointDistanceFromLine(m_parent->m_vertices.at(leftEdge.lower()), l, u);
+ return d < 0;
+}
+
+QRBTree<int>::Node *QTriangulator::ComplexToSimple::searchEdgeLeftOf(int edgeIndex) const
+{
+ QRBTree<int>::Node *current = m_edgeList.root;
+ QRBTree<int>::Node *result = 0;
+ while (current) {
+ if (edgeIsLeftOfEdge(edgeIndex, current->data)) {
+ current = current->left;
+ } else {
+ result = current;
+ current = current->right;
+ }
+ }
+ return result;
+}
+
+QRBTree<int>::Node *QTriangulator::ComplexToSimple::searchEdgeLeftOf(int edgeIndex, QRBTree<int>::Node *after) const
+{
+ if (!m_edgeList.root)
+ return after;
+ QRBTree<int>::Node *result = after;
+ QRBTree<int>::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;
+}
+
+QPair<QRBTree<int>::Node *, QRBTree<int>::Node *> QTriangulator::ComplexToSimple::bounds(const QPodPoint &point) const
+{
+ QRBTree<int>::Node *current = m_edgeList.root;
+ QPair<QRBTree<int>::Node *, QRBTree<int>::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());
+ int d = 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());
+ int d = 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());
+ int d = qPointDistanceFromLine(point, v1, v2);
+ Q_ASSERT(d <= 0);
+ if (d == 0) {
+ result.second = current;
+ current = current->right;
+ } else {
+ current = current->left;
+ }
+ }
+
+ return result;
+}
+
+QPair<QRBTree<int>::Node *, QRBTree<int>::Node *> QTriangulator::ComplexToSimple::outerBounds(const QPodPoint &point) const
+{
+ QRBTree<int>::Node *current = m_edgeList.root;
+ QPair<QRBTree<int>::Node *, QRBTree<int>::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());
+ int d = 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<int>::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());
+ int d = 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());
+ int d = qPointDistanceFromLine(point, v1, v2);
+ Q_ASSERT(d <= 0);
+ if (d == 0) {
+ current = current->right;
+ } else {
+ result.second = current;
+ current = current->left;
+ }
+ }
+
+ return result;
+}
+
+void QTriangulator::ComplexToSimple::splitEdgeListRange(QRBTree<int>::Node *leftmost, QRBTree<int>::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);
+ }
+}
+
+
+void QTriangulator::ComplexToSimple::reorderEdgeListRange(QRBTree<int>::Node *leftmost, QRBTree<int>::Node *rightmost)
+{
+ Q_ASSERT(leftmost && rightmost);
+
+ QRBTree<int>::Node *storeLeftmost = leftmost;
+ QRBTree<int>::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);
+}
+
+void QTriangulator::ComplexToSimple::sortEdgeList(const QPodPoint eventPoint)
+{
+ QIntersectionPoint eventPoint2 = 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<int>::Node *leftmost = m_edges.at(intersection.leftEdge).node;
+ QRBTree<int>::Node *rightmost = m_edges.at(intersection.rightEdge).node;
+
+ for (;;) {
+ QRBTree<int>::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(edge.from);
+ const QPodPoint &v = m_parent->m_vertices.at(edge.to);
+ if (!currentIntersectionPoint.isOnLine(u, v)) {
+ Q_ASSERT(!currentIntersectionPoint.isAccurate() || qCross(currentIntersectionPoint.upperLeft - u, v - u) != 0);
+ break;
+ }
+ leftmost = previous;
+ }
+
+ for (;;) {
+ QRBTree<int>::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(edge.from);
+ const QPodPoint &v = m_parent->m_vertices.at(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
+
+ }
+}
+
+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)) {
+ Event upperEvent = {m_parent->m_vertices.at(m_edges.at(i).upper()), Event::Upper, i};
+ Event lowerEvent = {m_parent->m_vertices.at(m_edges.at(i).lower()), 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());
+}
+
+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<QRBTree<int>::Node *, QRBTree<int>::Node *> range = bounds(event.point);
+ QRBTree<int>::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 = 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<int>::Node *left = m_edgeList.previous(m_edges.at(i).node);
+ QRBTree<int>::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<int>::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<int>::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'.
+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;
+ }
+}
+
+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;
+}
+
+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);
+}
+
+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<int>::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<QRBTree<int>::Node *, QRBTree<int>::Node *> b = outerBounds(event.point);
+ if (m_edgeList.root) {
+ QRBTree<int>::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(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<int>::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<int>::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
+}
+
+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<quint32> 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);
+ }
+}
+
+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;
+}
+
+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
+
+QTriangulator::ComplexToSimple::DebugDialog::DebugDialog(ComplexToSimple *parent, int currentVertex)
+ : m_parent(parent), m_vertex(currentVertex)
+{
+ QDataBuffer<QPodPoint> &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));
+}
+
+void QTriangulator::ComplexToSimple::DebugDialog::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ p.setRenderHint(QPainter::Antialiasing, true);
+ p.fillRect(rect(), Qt::black);
+ QDataBuffer<QPodPoint> &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<Edge> &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<int>::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<Split> &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);
+ }
+}
+
+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();
+}
+
+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();
+ }
+}
+
+void QTriangulator::ComplexToSimple::DebugDialog::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ m_lastMousePos = event->pos();
+ event->accept();
+}
+
+
+#endif
+
+//============================================================================//
+// QTriangulator::SimpleToMonotone //
+//============================================================================//
+
+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() != Q_TRIANGULATE_END_OF_POLYGON)
+ m_parent->m_indices.push_back(Q_TRIANGULATE_END_OF_POLYGON);
+ }
+}
+
+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) != 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.
+ }
+}
+
+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<int> 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);
+ }
+}
+
+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)));
+ //}
+}
+
+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 = qPointDistanceFromLine(m_parent->m_vertices.at(leftEdge.upper()), l, u);
+ // d < 0: left, d > 0: right, d == 0: on top
+ if (d == 0)
+ d = 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.
+QRBTree<int>::Node *QTriangulator::SimpleToMonotone::searchEdgeLeftOfEdge(int edgeIndex) const
+{
+ QRBTree<int>::Node *current = m_edgeList.root;
+ QRBTree<int>::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.
+QRBTree<int>::Node *QTriangulator::SimpleToMonotone::searchEdgeLeftOfPoint(int pointIndex) const
+{
+ QRBTree<int>::Node *current = m_edgeList.root;
+ QRBTree<int>::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 = qPointDistanceFromLine(m_parent->m_vertices.at(pointIndex), p1, p2);
+ if (d <= 0) {
+ current = current->left;
+ } else {
+ result = current;
+ current = current->right;
+ }
+ }
+ return result;
+}
+
+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 = 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);
+ }
+}
+
+void QTriangulator::SimpleToMonotone::classifyVertices()
+{
+ for (int i = 0; i < m_edges.size(); ++i)
+ classifyVertex(i);
+}
+
+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;
+}
+
+bool QTriangulator::SimpleToMonotone::pointIsInSector(int vertex, int sector)
+{
+ const QPodPoint &center = 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);
+}
+
+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;
+}
+
+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);
+}
+
+void QTriangulator::SimpleToMonotone::monotoneDecomposition()
+{
+ if (m_edges.isEmpty())
+ return;
+
+ Q_ASSERT(!m_edgeList.root);
+ QDataBuffer<std::pair<int, int> > diagonals;
+
+ 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(m_edges.at(i).from),
+ m_parent->m_vertices.at(m_edges.at(j).from), m_parent->m_vertices.at(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<int>::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(std::pair<int, int>(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(std::pair<int, int>(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(std::pair<int, int>(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(std::pair<int, int>(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<int>::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.verify());
+ } else {
+ leftEdgeNode = searchEdgeLeftOfEdge(i);
+ QRBTree<int>::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.verify());
+ }
+ 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(std::pair<int, int>(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(std::pair<int, int>(i, m_edges.at(i).helper));
+ if (m_edges.at(i).node) {
+ m_edgeList.deleteNode(m_edges.at(i).node);
+ Q_ASSERT(m_edgeList.verify());
+ } else {
+ qWarning("Inconsistent polygon. (#5)");
+ }
+ } else {
+ if (m_edges.at(m_edges.at(j).helper).type == MergeVertex)
+ diagonals.add(std::pair<int, int>(i, m_edges.at(j).helper));
+ if (m_edges.at(j).node) {
+ m_edgeList.deleteNode(m_edges.at(j).node);
+ Q_ASSERT(m_edgeList.verify());
+ } else {
+ qWarning("Inconsistent polygon. (#6)");
+ }
+ }
+ break;
+ }
+ }
+
+ for (int i = 0; i < diagonals.size(); ++i)
+ createDiagonal(diagonals.at(i).first, diagonals.at(i).second);
+}
+
+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 //
+//============================================================================//
+
+void QTriangulator::MonotoneToTriangles::decompose()
+{
+ QVector<quint32> result;
+ QDataBuffer<int> stack;
+ 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) != 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)
+{
+ QTriangulator triangulator;
+ triangulator.initialize(polygon, count, hint, matrix);
+ return triangulator.triangulate();
+}
+
+QTriangleSet qTriangulate(const QVectorPath &path, const QTransform &matrix, qreal lod)
+{
+ QTriangulator triangulator;
+ triangulator.initialize(path, matrix, lod);
+ return triangulator.triangulate();
+}
+
+QTriangleSet qTriangulate(const QPainterPath &path, const QTransform &matrix, qreal lod)
+{
+ QTriangulator triangulator;
+ triangulator.initialize(path, matrix, lod);
+ return triangulator.triangulate();
+}
+
+QPolylineSet qPolyline(const QVectorPath &path, const QTransform &matrix, qreal lod)
+{
+ QTriangulator triangulator;
+ triangulator.initialize(path, matrix, lod);
+ return triangulator.polyline();
+}
+
+QPolylineSet qPolyline(const QPainterPath &path, const QTransform &matrix, qreal lod)
+{
+ QTriangulator triangulator;
+ triangulator.initialize(path, matrix, lod);
+ return triangulator.polyline();
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qtriangulator_p.h b/src/opengl/gl2paintengineex/qtriangulator_p.h
new file mode 100644
index 000000000..da47666a5
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qtriangulator_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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 <QtCore/qvector.h>
+#include <QtGui/private/qvectorpath_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define Q_TRIANGULATE_END_OF_POLYGON quint32(-1)
+
+struct 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<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
+ QVector<quint32> indices; // [i[0], j[0], k[0], i[1], j[1], k[1], i[2], ...]
+};
+
+struct 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<qreal> vertices; // [x[0], y[0], x[1], y[1], x[2], ...]
+ QVector<quint32> indices;
+
+};
+
+// 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 qTriangulate(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
+QPolylineSet qPolyline(const QVectorPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
+QPolylineSet qPolyline(const QPainterPath &path, const QTransform &matrix = QTransform(), qreal lod = 1);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index 42317219b..ec01db062 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -13,8 +13,9 @@ include(../qbase.pri)
!win32:!embedded:!mac:CONFIG += x11
contains(QT_CONFIG, opengl):CONFIG += opengl
contains(QT_CONFIG, opengles1):CONFIG += opengles1
-contains(QT_CONFIG, opengles1):CONFIG += opengles1cl
+contains(QT_CONFIG, opengles1cl):CONFIG += opengles1cl
contains(QT_CONFIG, opengles2):CONFIG += opengles2
+contains(QT_CONFIG, egl):CONFIG += egl
HEADERS += qgl.h \
qgl_p.h \
@@ -22,13 +23,18 @@ HEADERS += qgl.h \
qglpixelbuffer.h \
qglpixelbuffer_p.h \
qglframebufferobject.h \
- qglextensions_p.h
+ qglframebufferobject_p.h \
+ qglextensions_p.h \
+ qglpaintdevice_p.h \
+
SOURCES += qgl.cpp \
qglcolormap.cpp \
qglpixelbuffer.cpp \
qglframebufferobject.cpp \
qglextensions.cpp \
+ qglpaintdevice.cpp \
+
!contains(QT_CONFIG, opengles2) {
HEADERS += qpaintengine_opengl_p.h
@@ -38,6 +44,7 @@ SOURCES += qgl.cpp \
!contains(QT_CONFIG, opengles1):!contains(QT_CONFIG, opengles1cl) {
HEADERS += qglshaderprogram.h \
qglpixmapfilter_p.h \
+ qgraphicsshadereffect_p.h \
qgraphicssystem_gl_p.h \
qwindowsurface_gl_p.h \
qpixmapdata_gl_p.h \
@@ -45,17 +52,24 @@ SOURCES += qgl.cpp \
gl2paintengineex/qglengineshadermanager_p.h \
gl2paintengineex/qgl2pexvertexarray_p.h \
gl2paintengineex/qpaintengineex_opengl2_p.h \
- gl2paintengineex/qglengineshadersource_p.h
+ gl2paintengineex/qglengineshadersource_p.h \
+ gl2paintengineex/qglcustomshaderstage_p.h \
+ gl2paintengineex/qtriangulatingstroker_p.h \
+ gl2paintengineex/qtriangulator_p.h
SOURCES += qglshaderprogram.cpp \
qglpixmapfilter.cpp \
+ qgraphicsshadereffect.cpp \
qgraphicssystem_gl.cpp \
qwindowsurface_gl.cpp \
qpixmapdata_gl.cpp \
gl2paintengineex/qglgradientcache.cpp \
gl2paintengineex/qglengineshadermanager.cpp \
gl2paintengineex/qgl2pexvertexarray.cpp \
- gl2paintengineex/qpaintengineex_opengl2.cpp
+ gl2paintengineex/qpaintengineex_opengl2.cpp \
+ gl2paintengineex/qglcustomshaderstage.cpp \
+ gl2paintengineex/qtriangulatingstroker.cpp \
+ gl2paintengineex/qtriangulator.cpp
}
@@ -63,9 +77,13 @@ x11 {
contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles1cl)|contains(QT_CONFIG, opengles2) {
SOURCES += qgl_x11egl.cpp \
qglpixelbuffer_egl.cpp \
- qgl_egl.cpp
+ qgl_egl.cpp \
+ qpixmapdata_x11gl_egl.cpp \
+ qwindowsurface_x11gl.cpp
- HEADERS += qgl_egl_p.h
+ HEADERS += qgl_egl_p.h \
+ qpixmapdata_x11gl_p.h \
+ qwindowsurface_x11gl_p.h
} else {
SOURCES += qgl_x11.cpp \
@@ -80,7 +98,7 @@ x11 {
LIBS_PRIVATE += -lfreetype
} else {
### Note: how does this compile with a non-system freetype?
- # This probably doesn't compile
+ # This probably does not compile
}
} else {
DEFINES *= QT_NO_FREETYPE
@@ -109,14 +127,12 @@ wince*: {
embedded {
SOURCES += qgl_qws.cpp \
- qglpaintdevice_qws.cpp \
qglpixelbuffer_egl.cpp \
qglscreen_qws.cpp \
qglwindowsurface_qws.cpp \
qgl_egl.cpp
- HEADERS += qglpaintdevice_qws_p.h \
- qglscreen_qws.h \
+ HEADERS += qglscreen_qws.h \
qglwindowsurface_qws_p.h \
qgl_egl_p.h
@@ -128,18 +144,3 @@ embedded {
}
INCLUDEPATH += ../3rdparty/harfbuzz/src
-
-wince*: {
- contains(QT_CONFIG,opengles1) {
- QMAKE_LIBS += "libGLES_CM.lib"
- }
- contains(QT_CONFIG,opengles1cl) {
- QMAKE_LIBS += "libGLES_CL.lib"
- }
- contains(QT_CONFIG,opengles2) {
- QMAKE_LIBS += "libGLESv2.lib"
- }
-
-} else {
- LIBS_PRIVATE += $$QMAKE_LIBS_OPENGL
-}
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 67c02f2f7..94b8aa5ee 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -59,6 +59,8 @@
# include <private/qt_mac_p.h>
#endif
+#include <qdatetime.h>
+
#include <stdlib.h> // malloc
#include "qpixmap.h"
@@ -74,7 +76,6 @@
#endif
#ifdef Q_WS_QWS
-#include <private/qglpaintdevice_qws_p.h>
#include <private/qglwindowsurface_qws_p.h>
#endif
@@ -103,7 +104,11 @@ QT_BEGIN_NAMESPACE
QGLExtensionFuncs QGLContextPrivate::qt_extensionFuncs;
#endif
-QThreadStorage<QGLThreadContext *> qgl_context_storage;
+struct QGLThreadContext {
+ QGLContext *context;
+};
+
+static QThreadStorage<QGLThreadContext *> qgl_context_storage;
Q_GLOBAL_STATIC(QGLFormat, qgl_default_format)
@@ -140,6 +145,74 @@ QGLSignalProxy *QGLSignalProxy::instance()
return theSignalProxy();
}
+
+class QGLEngineSelector
+{
+public:
+ QGLEngineSelector() : engineType(QPaintEngine::MaxUser)
+ {
+ }
+
+ void setPreferredPaintEngine(QPaintEngine::Type type) {
+ if (type == QPaintEngine::OpenGL || type == QPaintEngine::OpenGL2)
+ engineType = type;
+ }
+
+ QPaintEngine::Type preferredPaintEngine() {
+#ifdef Q_WS_MAC
+ // The ATI X1600 driver for Mac OS X does not support return
+ // values from functions in GLSL. Since working around this in
+ // the GL2 engine would require a big, ugly rewrite, we're
+ // falling back to the GL 1 engine..
+ static bool mac_x1600_check_done = false;
+ if (!mac_x1600_check_done) {
+ QGLWidget *tmp = 0;
+ if (!QGLContext::currentContext()) {
+ tmp = new QGLWidget();
+ tmp->makeCurrent();
+ }
+ if (strstr((char *) glGetString(GL_RENDERER), "X1600"))
+ engineType = QPaintEngine::OpenGL;
+ if (tmp)
+ delete tmp;
+ mac_x1600_check_done = true;
+ }
+#endif
+ if (engineType == QPaintEngine::MaxUser) {
+ // No user-set engine - use the defaults
+#if defined(QT_OPENGL_ES_2)
+ engineType = QPaintEngine::OpenGL2;
+#else
+ // We can't do this in the constructor for this object because it
+ // needs to be called *before* the QApplication constructor.
+ // Also check for the FragmentProgram extension in conjunction with
+ // the 2.0 version flag, to cover the case where we export the display
+ // from an old GL 1.1 server to a GL 2.x client. In that case we can't
+ // use GL 2.0.
+ if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)
+ && (QGLExtensions::glExtensions & QGLExtensions::FragmentProgram)
+ && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty())
+ engineType = QPaintEngine::OpenGL2;
+ else
+ engineType = QPaintEngine::OpenGL;
+#endif
+ }
+ return engineType;
+ }
+
+private:
+ QPaintEngine::Type engineType;
+};
+
+Q_GLOBAL_STATIC(QGLEngineSelector, qgl_engine_selector)
+
+
+bool qt_gl_preferGL2Engine()
+{
+ return qgl_engine_selector()->preferredPaintEngine() == QPaintEngine::OpenGL2;
+}
+
+
/*!
\namespace QGL
\inmodule QtOpenGL
@@ -147,7 +220,7 @@ QGLSignalProxy *QGLSignalProxy::instance()
\brief The QGL namespace specifies miscellaneous identifiers used
in the Qt OpenGL module.
- \ingroup multimedia
+ \ingroup painting-3D
*/
/*!
@@ -180,6 +253,32 @@ QGLSignalProxy *QGLSignalProxy::instance()
\sa {Sample Buffers Example}
*/
+/*!
+ \fn void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType)
+
+ \since 4.6
+
+ Sets the preferred OpenGL paint engine that is used to draw onto
+ QGLWidget, QGLPixelBuffer and QGLFramebufferObject targets with QPainter
+ in Qt.
+
+ The \a engineType parameter specifies which of the GL engines to
+ use. Only \c QPaintEngine::OpenGL and \c QPaintEngine::OpenGL2 are
+ valid parameters to this function. All other values are ignored.
+
+ By default, the \c QPaintEngine::OpenGL2 engine is used if GL/GLES
+ version 2.0 is available, otherwise \c QPaintEngine::OpenGL is
+ used.
+
+ \warning This function must be called before the QApplication
+ constructor is called.
+*/
+void QGL::setPreferredPaintEngine(QPaintEngine::Type engineType)
+{
+ qgl_engine_selector()->setPreferredPaintEngine(engineType);
+}
+
+
/*****************************************************************************
QGLFormat implementation
*****************************************************************************/
@@ -190,7 +289,7 @@ QGLSignalProxy *QGLSignalProxy::instance()
\brief The QGLFormat class specifies the display format of an OpenGL
rendering context.
- \ingroup multimedia
+ \ingroup painting-3D
A display format has several characteristics:
\list
@@ -203,13 +302,14 @@ QGLSignalProxy *QGLSignalProxy::instance()
\i \link setStereo() Stereo buffers.\endlink
\i \link setDirectRendering() Direct rendering.\endlink
\i \link setOverlay() Presence of an overlay.\endlink
- \i \link setPlane() The plane of an overlay format.\endlink
+ \i \link setPlane() Plane of an overlay.\endlink
\i \link setSampleBuffers() Multisample buffers.\endlink
\endlist
- You can also specify preferred bit depths for the depth buffer,
- alpha buffer, accumulation buffer and the stencil buffer with the
- functions: setDepthBufferSize(), setAlphaBufferSize(),
+ You can also specify preferred bit depths for the color buffer,
+ depth buffer, alpha buffer, accumulation buffer and the stencil
+ buffer with the functions: setRedBufferSize(), setGreenBufferSize(),
+ setBlueBufferSize(), setDepthBufferSize(), setAlphaBufferSize(),
setAccumBufferSize() and setStencilBufferSize().
Note that even if you specify that you prefer a 32 bit depth
@@ -250,6 +350,8 @@ QGLSignalProxy *QGLSignalProxy::instance()
\sa QGLContext, QGLWidget
*/
+#ifndef QT_OPENGL_ES
+
static inline void transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4])
{
#define M(row,col) m[col*4+row]
@@ -292,20 +394,23 @@ static inline GLint qgluProject(GLdouble objx, GLdouble objy, GLdouble objz,
return GL_TRUE;
}
+#endif // !QT_OPENGL_ES
+
/*!
- Constructs a QGLFormat object with the factory default settings:
+ Constructs a QGLFormat object with the following default settings:
\list
\i \link setDoubleBuffer() Double buffer:\endlink Enabled.
\i \link setDepth() Depth buffer:\endlink Enabled.
\i \link setRgba() RGBA:\endlink Enabled (i.e., color index disabled).
\i \link setAlpha() Alpha channel:\endlink Disabled.
\i \link setAccum() Accumulator buffer:\endlink Disabled.
- \i \link setStencil() Stencil buffer:\endlink Disabled.
+ \i \link setStencil() Stencil buffer:\endlink Enabled.
\i \link setStereo() Stereo:\endlink Disabled.
\i \link setDirectRendering() Direct rendering:\endlink Enabled.
\i \link setOverlay() Overlay:\endlink Disabled.
\i \link setPlane() Plane:\endlink 0 (i.e., normal plane).
- \i \link setSampleBuffers() Multisample buffers:\endlink Disabled.
+ \i \link setSampleBuffers() Multisample buffers:\endlink Enabled on
+ OpenGL/ES 2.0, disabled on other platforms.
\endlist
*/
@@ -316,26 +421,26 @@ QGLFormat::QGLFormat()
/*!
- Creates a QGLFormat object that is a copy of the current \link
- defaultFormat() application default format\endlink.
+ Creates a QGLFormat object that is a copy of the current
+ defaultFormat().
- If \a options is not 0, this copy is modified by these format
- options. The \a options parameter should be \c FormatOption values
- OR'ed together.
+ If \a options is not 0, the default format is modified by the
+ specified format options. The \a options parameter should be
+ QGL::FormatOption values OR'ed together.
This constructor makes it easy to specify a certain desired format
in classes derived from QGLWidget, for example:
\snippet doc/src/snippets/code/src_opengl_qgl.cpp 3
- Note that there are \c FormatOption values to turn format settings
- both on and off, e.g. \c DepthBuffer and \c NoDepthBuffer,
- \c DirectRendering and \c IndirectRendering, etc.
+ Note that there are QGL::FormatOption values to turn format settings
+ both on and off, e.g. QGL::DepthBuffer and QGL::NoDepthBuffer,
+ QGL::DirectRendering and QGL::IndirectRendering, etc.
The \a plane parameter defaults to 0 and is the plane which this
format should be associated with. Not all OpenGL implementations
supports overlay/underlay rendering planes.
- \sa defaultFormat(), setOption()
+ \sa defaultFormat(), setOption(), setPlane()
*/
QGLFormat::QGLFormat(QGL::FormatOptions options, int plane)
@@ -349,13 +454,26 @@ QGLFormat::QGLFormat(QGL::FormatOptions options, int plane)
}
/*!
+ \internal
+*/
+void QGLFormat::detach()
+{
+ if (d->ref != 1) {
+ QGLFormatPrivate *newd = new QGLFormatPrivate(d);
+ if (!d->ref.deref())
+ delete d;
+ d = newd;
+ }
+}
+
+/*!
Constructs a copy of \a other.
*/
QGLFormat::QGLFormat(const QGLFormat &other)
{
- d = new QGLFormatPrivate;
- *d = *other.d;
+ d = other.d;
+ d->ref.ref();
}
/*!
@@ -364,7 +482,12 @@ QGLFormat::QGLFormat(const QGLFormat &other)
QGLFormat &QGLFormat::operator=(const QGLFormat &other)
{
- *d = *other.d;
+ if (d != other.d) {
+ other.d->ref.ref();
+ if (!d->ref.deref())
+ delete d;
+ d = other.d;
+ }
return *this;
}
@@ -373,7 +496,8 @@ QGLFormat &QGLFormat::operator=(const QGLFormat &other)
*/
QGLFormat::~QGLFormat()
{
- delete d;
+ if (!d->ref.deref())
+ delete d;
}
/*!
@@ -649,6 +773,7 @@ int QGLFormat::samples() const
*/
void QGLFormat::setSamples(int numSamples)
{
+ detach();
if (numSamples < 0) {
qWarning("QGLFormat::setSamples: Cannot have negative number of samples per pixel %d", numSamples);
return;
@@ -676,6 +801,7 @@ void QGLFormat::setSamples(int numSamples)
*/
void QGLFormat::setSwapInterval(int interval)
{
+ detach();
d->swapInterval = interval;
}
@@ -721,7 +847,7 @@ void QGLFormat::setOverlay(bool enable)
is 0, which means the normal plane. The default for overlay
formats is 1, which is the first overlay plane.
- \sa setPlane()
+ \sa setPlane(), defaultOverlayFormat()
*/
int QGLFormat::plane() const
{
@@ -743,6 +869,7 @@ int QGLFormat::plane() const
*/
void QGLFormat::setPlane(int plane)
{
+ detach();
d->pln = plane;
}
@@ -754,6 +881,7 @@ void QGLFormat::setPlane(int plane)
void QGLFormat::setOption(QGL::FormatOptions opt)
{
+ detach();
if (opt & 0xffff)
d->opts |= opt;
else
@@ -783,6 +911,7 @@ bool QGLFormat::testOption(QGL::FormatOptions opt) const
*/
void QGLFormat::setDepthBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size %d", size);
return;
@@ -809,6 +938,7 @@ int QGLFormat::depthBufferSize() const
*/
void QGLFormat::setRedBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setRedBufferSize: Cannot set negative red buffer size %d", size);
return;
@@ -837,6 +967,7 @@ int QGLFormat::redBufferSize() const
*/
void QGLFormat::setGreenBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setGreenBufferSize: Cannot set negative green buffer size %d", size);
return;
@@ -865,6 +996,7 @@ int QGLFormat::greenBufferSize() const
*/
void QGLFormat::setBlueBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size %d", size);
return;
@@ -892,6 +1024,7 @@ int QGLFormat::blueBufferSize() const
*/
void QGLFormat::setAlphaBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size %d", size);
return;
@@ -918,6 +1051,7 @@ int QGLFormat::alphaBufferSize() const
*/
void QGLFormat::setAccumBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size %d", size);
return;
@@ -942,6 +1076,7 @@ int QGLFormat::accumBufferSize() const
*/
void QGLFormat::setStencilBufferSize(int size)
{
+ detach();
if (size < 0) {
qWarning("QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size %d", size);
return;
@@ -1137,11 +1272,11 @@ QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags()
if (cachedDefault) {
return defaultVersionFlags;
} else {
- cachedDefault = true;
if (!hasOpenGL())
return defaultVersionFlags;
dummy = new QGLWidget;
dummy->makeCurrent(); // glGetString() needs a current context
+ cachedDefault = true;
}
}
@@ -1161,8 +1296,8 @@ QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags()
/*!
- Returns the default QGLFormat for the application. All QGLWidgets
- that are created use this format unless another format is
+ Returns the default QGLFormat for the application. All QGLWidget
+ objects that are created use this format unless another format is
specified, e.g. when they are constructed.
If no special default format has been set using
@@ -1195,7 +1330,7 @@ void QGLFormat::setDefaultFormat(const QGLFormat &f)
/*!
Returns the default QGLFormat for overlay contexts.
- The factory default overlay format is:
+ The default overlay format is:
\list
\i \link setDoubleBuffer() Double buffer:\endlink Disabled.
\i \link setDepth() Depth buffer:\endlink Disabled.
@@ -1206,6 +1341,7 @@ void QGLFormat::setDefaultFormat(const QGLFormat &f)
\i \link setStereo() Stereo:\endlink Disabled.
\i \link setDirectRendering() Direct rendering:\endlink Enabled.
\i \link setOverlay() Overlay:\endlink Disabled.
+ \i \link setSampleBuffers() Multisample buffers:\endlink Disabled.
\i \link setPlane() Plane:\endlink 1 (i.e., first overlay plane).
\endlist
@@ -1248,21 +1384,30 @@ void QGLFormat::setDefaultOverlayFormat(const QGLFormat &f)
/*!
- Returns true if all the options of the two QGLFormats are equal;
- otherwise returns false.
+ Returns true if all the options of the two QGLFormat objects
+ \a a and \a b are equal; otherwise returns false.
+
+ \relates QGLFormat
*/
bool operator==(const QGLFormat& a, const QGLFormat& b)
{
return (int) a.d->opts == (int) b.d->opts && a.d->pln == b.d->pln && a.d->alphaSize == b.d->alphaSize
&& a.d->accumSize == b.d->accumSize && a.d->stencilSize == b.d->stencilSize
- && a.d->depthSize == b.d->depthSize;
+ && a.d->depthSize == b.d->depthSize
+ && a.d->redSize == b.d->redSize
+ && a.d->greenSize == b.d->greenSize
+ && a.d->blueSize == b.d->blueSize
+ && a.d->numSamples == b.d->numSamples
+ && a.d->swapInterval == b.d->swapInterval;
}
/*!
- Returns false if all the options of the two QGLFormats are equal;
- otherwise returns true.
+ Returns false if all the options of the two QGLFormat objects
+ \a a and \a b are equal; otherwise returns true.
+
+ \relates QGLFormat
*/
bool operator!=(const QGLFormat& a, const QGLFormat& b)
@@ -1273,6 +1418,45 @@ bool operator!=(const QGLFormat& a, const QGLFormat& b)
/*****************************************************************************
QGLContext implementation
*****************************************************************************/
+
+QGLContextGroup::~QGLContextGroup()
+{
+ // Clear any remaining QGLSharedResourceGuard objects on the group.
+ QGLSharedResourceGuard *guard = m_guards;
+ while (guard != 0) {
+ guard->m_group = 0;
+ guard->m_id = 0;
+ guard = guard->m_next;
+ }
+}
+
+void QGLContextGroup::addGuard(QGLSharedResourceGuard *guard)
+{
+ if (m_guards)
+ m_guards->m_prev = guard;
+ guard->m_next = m_guards;
+ guard->m_prev = 0;
+ m_guards = guard;
+}
+
+void QGLContextGroup::removeGuard(QGLSharedResourceGuard *guard)
+{
+ if (guard->m_next)
+ guard->m_next->m_prev = guard->m_prev;
+ if (guard->m_prev)
+ guard->m_prev->m_next = guard->m_next;
+ else
+ m_guards = guard->m_next;
+}
+
+QGLContextPrivate::~QGLContextPrivate()
+{
+ if (!group->m_refs.deref()) {
+ Q_ASSERT(group->context() == q_ptr);
+ delete group;
+ }
+}
+
void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
{
Q_Q(QGLContext);
@@ -1301,17 +1485,17 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
#endif
#if defined(QT_OPENGL_ES)
eglContext = 0;
+ eglSurface = EGL_NO_SURFACE;
#endif
- pbo = 0;
fbo = 0;
crWin = false;
initDone = false;
sharing = false;
- clear_on_painter_begin = true;
max_texture_size = -1;
version_flags_cached = false;
version_flags = QGLFormat::OpenGL_Version_None;
current_fbo = 0;
+ default_fbo = 0;
active_engine = 0;
}
@@ -1409,7 +1593,10 @@ QGLTextureCache::QGLTextureCache()
Q_ASSERT(qt_gl_texture_cache == 0);
qt_gl_texture_cache = this;
- QImagePixmapCleanupHooks::instance()->addPixmapHook(pixmapCleanupHook);
+ QImagePixmapCleanupHooks::instance()->addPixmapModificationHook(cleanupTextures);
+#ifdef Q_WS_X11
+ QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(cleanupPixmapSurfaces);
+#endif
QImagePixmapCleanupHooks::instance()->addImageHook(imageCleanupHook);
}
@@ -1417,7 +1604,10 @@ QGLTextureCache::~QGLTextureCache()
{
qt_gl_texture_cache = 0;
- QImagePixmapCleanupHooks::instance()->removePixmapHook(pixmapCleanupHook);
+ QImagePixmapCleanupHooks::instance()->removePixmapModificationHook(cleanupTextures);
+#ifdef Q_WS_X11
+ QImagePixmapCleanupHooks::instance()->removePixmapDestructionHook(cleanupPixmapSurfaces);
+#endif
QImagePixmapCleanupHooks::instance()->removeImageHook(imageCleanupHook);
}
@@ -1444,7 +1634,7 @@ bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId)
for (int i = 0; i < keys.size(); ++i) {
QGLTexture *tex = m_cache.object(keys.at(i));
if (tex->id == textureId && tex->context == ctx) {
- tex->clean = true; // forces a glDeleteTextures() call
+ tex->options |= QGLContext::MemoryManagedBindOption; // forces a glDeleteTextures() call
m_cache.remove(keys.at(i));
return true;
}
@@ -1480,27 +1670,35 @@ void QGLTextureCache::imageCleanupHook(qint64 cacheKey)
if (qApp->thread() != QThread::currentThread())
return;
QGLTexture *texture = instance()->getTexture(cacheKey);
- if (texture && texture->clean)
+ if (texture && texture->options & QGLContext::MemoryManagedBindOption)
instance()->remove(cacheKey);
}
-void QGLTextureCache::pixmapCleanupHook(QPixmap* pixmap)
+void QGLTextureCache::cleanupTextures(QPixmap* pixmap)
{
// ### remove when the GL texture cache becomes thread-safe
if (qApp->thread() == QThread::currentThread()) {
const qint64 cacheKey = pixmap->cacheKey();
QGLTexture *texture = instance()->getTexture(cacheKey);
- if (texture && texture->clean)
+ if (texture && texture->options & QGLContext::MemoryManagedBindOption)
instance()->remove(cacheKey);
}
+}
+
#if defined(Q_WS_X11)
- QPixmapData *pd = pixmap->data_ptr();
- // Only need to delete the gl surface if the pixmap is about to be deleted
- if (pd->ref == 0)
+void QGLTextureCache::cleanupPixmapSurfaces(QPixmap* pixmap)
+{
+ // Remove any bound textures first:
+ cleanupTextures(pixmap);
+
+ QPixmapData *pd = pixmap->data_ptr().data();
+ if (pd->classId() == QPixmapData::X11Class) {
+ Q_ASSERT(pd->ref == 1); // Make sure reference counting isn't broken
QGLContextPrivate::destroyGlSurfaceForPixmap(pd);
-#endif
+ }
}
+#endif
void QGLTextureCache::deleteIfEmpty()
{
@@ -1554,7 +1752,7 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
\class QGLContext
\brief The QGLContext class encapsulates an OpenGL rendering context.
- \ingroup multimedia
+ \ingroup painting-3D
An OpenGL rendering context is a complete set of OpenGL state
variables. The rendering context's \l {QGL::FormatOption} {format}
@@ -1579,6 +1777,47 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
Please note that QGLContext is not thread safe.
*/
+/*!
+ \enum QGLContext::BindOption
+ \since 4.6
+
+ A set of options to decide how to bind a texture using bindTexture().
+
+ \value NoBindOption Don't do anything, pass the texture straight
+ through.
+
+ \value InvertedYBindOption Specifies that the texture should be flipped
+ over the X axis so that the texture coordinate 0,0 corresponds to
+ the top left corner. Inverting the texture implies a deep copy
+ prior to upload.
+
+ \value MipmapBindOption Specifies that bindTexture() should try
+ to generate mipmaps. If the GL implementation supports the \c
+ GL_SGIS_generate_mipmap extension, mipmaps will be automatically
+ generated for the texture. Mipmap generation is only supported for
+ the \c GL_TEXTURE_2D target.
+
+ \value PremultipliedAlphaBindOption Specifies that the image should be
+ uploaded with premultiplied alpha and does a conversion accordingly.
+
+ \value LinearFilteringBindOption Specifies that the texture filtering
+ should be set to GL_LINEAR. Default is GL_NEAREST. If mipmap is
+ also enabled, filtering will be set to GL_LINEAR_MIPMAP_LINEAR.
+
+ \value DefaultBindOption In Qt 4.5 and earlier, bindTexture()
+ would mirror the image and automatically generate mipmaps. This
+ option helps preserve this default behavior.
+
+ \omitvalue CanFlipNativePixmapBindOption Used by x11 from pixmap to choose
+ wether or not it can bind the pixmap upside down or not.
+
+ \omitvalue MemoryManagedBindOption Used by paint engines to
+ indicate that the pixmap should be memory managed along side with
+ the pixmap/image that it stems from, e.g. installing destruction
+ hooks in them.
+
+ \omitvalue InternalBindOption
+*/
/*!
\obsolete
@@ -1599,8 +1838,8 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
*/
QGLContext::QGLContext(const QGLFormat &format, QPaintDevice *device)
+ : d_ptr(new QGLContextPrivate(this))
{
- d_ptr = new QGLContextPrivate(this);
Q_D(QGLContext);
d->init(device, format);
}
@@ -1622,8 +1861,8 @@ QGLContext::QGLContext(const QGLFormat &format, QPaintDevice *device)
\sa format(), isValid()
*/
QGLContext::QGLContext(const QGLFormat &format)
+ : d_ptr(new QGLContextPrivate(this))
{
- d_ptr = new QGLContextPrivate(this);
Q_D(QGLContext);
d->init(0, format);
}
@@ -1634,24 +1873,18 @@ QGLContext::QGLContext(const QGLFormat &format)
QGLContext::~QGLContext()
{
- Q_D(QGLContext);
// remove any textures cached in this context
QGLTextureCache::instance()->removeContextTextures(this);
QGLTextureCache::deleteIfEmpty(); // ### thread safety
+ d_ptr->group->cleanupResources(this);
+
QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
reset();
- delete d;
}
void QGLContextPrivate::cleanup()
{
- Q_Q(QGLContext);
- if (pbo) {
- QGLContext *ctx = q;
- glDeleteBuffers(1, &pbo);
- pbo = 0;
- }
}
typedef QHash<QString, GLuint> QGLDDSCache;
@@ -1768,6 +2001,32 @@ GLuint QGLContext::bindTexture(const QString &fileName)
return tx_id;
}
+static inline QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format)
+{
+ if (texture_format == GL_BGRA) {
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ return ((src_pixel << 24) & 0xff000000)
+ | ((src_pixel >> 24) & 0x000000ff)
+ | ((src_pixel << 8) & 0x00ff0000)
+ | ((src_pixel >> 8) & 0x0000ff00);
+ } else {
+ return src_pixel;
+ }
+ } else { // GL_RGBA
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ return (src_pixel << 8) | ((src_pixel >> 24) & 0xff);
+ } else {
+ return ((src_pixel << 16) & 0xff0000)
+ | ((src_pixel >> 16) & 0xff)
+ | (src_pixel & 0xff00ff00);
+ }
+ }
+}
+
+QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format)
+{
+ return qt_gl_convertToGLFormatHelper(src_pixel, texture_format);
+}
static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format)
{
@@ -1785,8 +2044,8 @@ static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum textu
int sbpl = img.bytesPerLine();
int dbpl = dst.bytesPerLine();
- int ix = 0x00010000 / sx;
- int iy = 0x00010000 / sy;
+ int ix = int(0x00010000 / sx);
+ int iy = int(0x00010000 / sy);
quint32 basex = int(0.5 * ix);
quint32 srcy = int(0.5 * iy);
@@ -1796,25 +2055,7 @@ static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum textu
const uint *src = (const quint32 *) (srcPixels - (srcy >> 16) * sbpl);
int srcx = basex;
for (int x=0; x<target_width; ++x) {
- uint src_pixel = src[srcx >> 16];
- if (texture_format == GL_BGRA) {
- if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- dest[x] = ((src_pixel << 24) & 0xff000000)
- | ((src_pixel >> 24) & 0x000000ff)
- | ((src_pixel << 8) & 0x00ff0000)
- | ((src_pixel >> 8) & 0x0000ff00);
- } else {
- dest[x] = src_pixel;
- }
- } else { // GL_RGBA
- if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
- dest[x] = (src_pixel << 8) | ((src_pixel >> 24) & 0xff);
- } else {
- dest[x] = ((src_pixel << 16) & 0xff0000)
- | ((src_pixel >> 16) & 0xff)
- | (src_pixel & 0xff00ff00);
- }
- }
+ dest[x] = qt_gl_convertToGLFormatHelper(src[srcx >> 16], texture_format);
srcx += ix;
}
dest = (quint32 *)(((uchar *) dest) + dbpl);
@@ -1888,7 +2129,8 @@ QImage QGLContextPrivate::convertToGLFormat(const QImage &image, bool force_prem
}
/*! \internal */
-QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, bool clean)
+QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
+ QGLContext::BindOptions options)
{
const qint64 key = image.cacheKey();
QGLTexture *texture = textureCacheLookup(key, target);
@@ -1898,107 +2140,217 @@ QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
}
if (!texture)
- texture = bindTexture(image, target, format, key, clean);
+ texture = bindTexture(image, target, format, key, options);
// NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
Q_ASSERT(texture);
if (texture->id > 0)
- const_cast<QImage &>(image).data_ptr()->is_cached = true;
+ QImagePixmapCleanupHooks::enableCleanupHooks(image);
return texture;
}
-QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
- const qint64 key, bool clean)
+// #define QGL_BIND_TEXTURE_DEBUG
+
+QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat,
+ const qint64 key, QGLContext::BindOptions options)
{
Q_Q(QGLContext);
- QGLContext *ctx = q;
-
- bool use_pbo = false;
- if (QGLExtensions::glExtensions & QGLExtensions::PixelBufferObject) {
-
- use_pbo = qt_resolve_buffer_extensions(ctx);
- if (use_pbo && pbo == 0)
- glGenBuffers(1, &pbo);
- }
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf("QGLContextPrivate::bindTexture(), imageSize=(%d,%d), internalFormat =0x%x, options=%x\n",
+ image.width(), image.height(), internalFormat, int(options));
+ QTime time;
+ time.start();
+#endif
- // the GL_BGRA format is only present in GL version >= 1.2
- GLenum texture_format = (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2)
- ? GL_BGRA : GL_RGBA;
+#ifndef QT_NO_DEBUG
+ // Reset the gl error stack...git
+ while (glGetError() != GL_NO_ERROR) ;
+#endif
// Scale the pixmap if needed. GL textures needs to have the
// dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL
// 2.0 or use the GL_TEXTURE_RECTANGLE texture target
int tx_w = qt_next_power_of_two(image.width());
int tx_h = qt_next_power_of_two(image.height());
- bool scale = false;
QImage img = image;
- if (( !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) &&
- !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0) )
+ if (!(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures)
+ && !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0)
&& (target == GL_TEXTURE_2D && (tx_w != image.width() || tx_h != image.height())))
{
- scale = true;
+ img = img.scaled(tx_w, tx_h);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - upscaled to %dx%d (%d ms)\n", tx_w, tx_h, time.elapsed());
+
+#endif
}
+ GLuint filtering = options & QGLContext::LinearFilteringBindOption ? GL_LINEAR : GL_NEAREST;
+
GLuint tx_id;
glGenTextures(1, &tx_id);
glBindTexture(target, tx_id);
- glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(target, GL_TEXTURE_MAG_FILTER, filtering);
+
+#if defined(QT_OPENGL_ES_2)
+ bool genMipmap = false;
+#endif
if (glFormat.directRendering()
- && QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap
- && target == GL_TEXTURE_2D && !clean)
+ && (QGLExtensions::glExtensions & QGLExtensions::GenerateMipmap)
+ && target == GL_TEXTURE_2D
+ && (options & QGLContext::MipmapBindOption))
{
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - generating mipmaps (%d ms)\n", time.elapsed());
+#endif
+#if !defined(QT_OPENGL_ES_2)
glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
#ifndef QT_OPENGL_ES
glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
#else
glTexParameterf(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
#endif
- glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+#else
+ glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
+ genMipmap = true;
+#endif
+ glTexParameterf(target, GL_TEXTURE_MIN_FILTER, options & QGLContext::LinearFilteringBindOption
+ ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST);
+ } else {
+ glTexParameterf(target, GL_TEXTURE_MIN_FILTER, filtering);
+ }
- // Mipmap generation causes huge slowdown with PBO's for some reason
- use_pbo = false;
+ QImage::Format target_format = img.format();
+ bool premul = options & QGLContext::PremultipliedAlphaBindOption;
+ GLenum externalFormat;
+ GLuint pixel_type;
+ if (QGLExtensions::glExtensions & QGLExtensions::BGRATextureFormat) {
+ externalFormat = GL_BGRA;
+ pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
} else {
- glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ externalFormat = GL_RGBA;
+ pixel_type = GL_UNSIGNED_BYTE;
}
- uchar *ptr = 0;
- if (use_pbo) {
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
- glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, img.width() * img.height() * 4, 0, GL_STREAM_DRAW_ARB);
- ptr = reinterpret_cast<uchar *>(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB));
+ switch (target_format) {
+ case QImage::Format_ARGB32:
+ if (premul) {
+ img = img.convertToFormat(target_format = QImage::Format_ARGB32_Premultiplied);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting ARGB32 -> ARGB32_Premultiplied (%d ms) \n", time.elapsed());
+#endif
+ }
+ break;
+ case QImage::Format_ARGB32_Premultiplied:
+ if (!premul) {
+ img = img.convertToFormat(target_format = QImage::Format_ARGB32);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting ARGB32_Premultiplied -> ARGB32 (%d ms)\n", time.elapsed());
+#endif
+ }
+ break;
+ case QImage::Format_RGB16:
+ pixel_type = GL_UNSIGNED_SHORT_5_6_5;
+ externalFormat = GL_RGB;
+ internalFormat = GL_RGB;
+ break;
+ case QImage::Format_RGB32:
+ break;
+ default:
+ if (img.hasAlphaChannel()) {
+ img = img.convertToFormat(premul
+ ? QImage::Format_ARGB32_Premultiplied
+ : QImage::Format_ARGB32);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting to 32-bit alpha format (%d ms)\n", time.elapsed());
+#endif
+ } else {
+ img = img.convertToFormat(QImage::Format_RGB32);
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - converting to 32-bit (%d ms)\n", time.elapsed());
+#endif
+ }
}
- QImage::Format target_format = img.format();
- // Note: the clean param is only true when a texture is bound
- // from the QOpenGLPaintEngine - in that case we have to force
- // a premultiplied texture format
- if (clean || img.format() != QImage::Format_ARGB32)
- target_format = QImage::Format_ARGB32_Premultiplied;
- if (img.format() != target_format)
- img = img.convertToFormat(target_format);
-
- if (ptr) {
- QImage buffer(ptr, img.width(), img.height(), target_format);
- convertToGLFormatHelper(buffer, img, texture_format);
- glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB);
- glTexImage2D(target, 0, format, img.width(), img.height(), 0, texture_format,
- GL_UNSIGNED_BYTE, 0);
- } else {
- QImage tx(scale ? QSize(tx_w, tx_h) : img.size(), target_format);
- convertToGLFormatHelper(tx, img, texture_format);
- glTexImage2D(target, 0, format, tx.width(), tx.height(), 0, texture_format,
- GL_UNSIGNED_BYTE, tx.bits());
+ if (options & QGLContext::InvertedYBindOption) {
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - flipping bits over y (%d ms)\n", time.elapsed());
+#endif
+ if (img.isDetached()) {
+ int ipl = img.bytesPerLine() / 4;
+ int h = img.height();
+ for (int y=0; y<h/2; ++y) {
+ int *a = (int *) img.scanLine(y);
+ int *b = (int *) img.scanLine(h - y - 1);
+ for (int x=0; x<ipl; ++x)
+ qSwap(a[x], b[x]);
+ }
+ } else {
+ // Create a new image and copy across. If we use the
+ // above in-place code then a full copy of the image is
+ // made before the lines are swapped, which processes the
+ // data twice. This version should only do it once.
+ img = img.mirrored();
+ }
+ }
+
+ if (externalFormat == GL_RGBA) {
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - doing byte swapping (%d ms)\n", time.elapsed());
+#endif
+ // The only case where we end up with a depth different from
+ // 32 in the switch above is for the RGB16 case, where we set
+ // the format to GL_RGB
+ Q_ASSERT(img.depth() == 32);
+ const int width = img.width();
+ const int height = img.height();
+
+ if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV
+ || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) {
+ for (int i=0; i < height; ++i) {
+ uint *p = (uint *) img.scanLine(i);
+ for (int x=0; x<width; ++x)
+ p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
+ }
+ } else {
+ for (int i=0; i < height; ++i) {
+ uint *p = (uint *) img.scanLine(i);
+ for (int x=0; x<width; ++x)
+ p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff);
+ }
+ }
}
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ printf(" - uploading, image.format=%d, externalFormat=0x%x, internalFormat=0x%x, pixel_type=0x%x\n",
+ img.format(), externalFormat, internalFormat, pixel_type);
+#endif
+
+ const QImage &constRef = img; // to avoid detach in bits()...
+ glTexImage2D(target, 0, internalFormat, img.width(), img.height(), 0, externalFormat,
+ pixel_type, constRef.bits());
+#if defined(QT_OPENGL_ES_2)
+ if (genMipmap)
+ glGenerateMipmap(target);
+#endif
+#ifndef QT_NO_DEBUG
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR) {
+ qWarning(" - texture upload failed, error code 0x%x\n", error);
+ }
+#endif
+
+#ifdef QGL_BIND_TEXTURE_DEBUG
+ static int totalUploadTime = 0;
+ totalUploadTime += time.elapsed();
+ printf(" - upload done in (%d ms) time=%d\n", time.elapsed(), totalUploadTime);
+#endif
- if (use_pbo)
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
// this assumes the size of a texture is always smaller than the max cache size
int cost = img.width()*img.height()*4/1024;
- QGLTexture *texture = new QGLTexture(q, tx_id, target, clean, false);
+ QGLTexture *texture = new QGLTexture(q, tx_id, target, options);
QGLTextureCache::instance()->insert(q, key, texture, cost);
return texture;
}
@@ -2008,7 +2360,7 @@ QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum targe
Q_Q(QGLContext);
QGLTexture *texture = QGLTextureCache::instance()->getTexture(key);
if (texture && texture->target == target
- && (texture->context == q || qgl_share_reg()->checkSharing(q, texture->context)))
+ && (texture->context == q || QGLContext::areSharing(q, texture->context)))
{
return texture;
}
@@ -2017,7 +2369,7 @@ QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum targe
/*! \internal */
-QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean, bool canInvert)
+QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, QGLContext::BindOptions options)
{
Q_Q(QGLContext);
QPixmapData *pd = pixmap.pixmapData();
@@ -2030,6 +2382,9 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target,
return data->texture();
}
}
+#else
+ Q_UNUSED(pd);
+ Q_UNUSED(q);
#endif
const qint64 key = pixmap.cacheKey();
@@ -2041,10 +2396,10 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target,
#if defined(Q_WS_X11)
// Try to use texture_from_pixmap
- if (pd->classId() == QPixmapData::X11Class) {
- texture = bindTextureFromNativePixmap(pd, key, canInvert);
+ if (pd->classId() == QPixmapData::X11Class && pd->pixelType() == QPixmapData::PixmapType) {
+ texture = bindTextureFromNativePixmap(pd, key, options);
if (texture) {
- texture->clean = clean;
+ texture->options |= QGLContext::MemoryManagedBindOption;
texture->boundPixmap = pd;
boundPixmaps.insert(pd, QPixmap(pixmap));
}
@@ -2052,12 +2407,12 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target,
#endif
if (!texture)
- texture = bindTexture(pixmap.toImage(), target, format, key, clean);
+ texture = bindTexture(pixmap.toImage(), target, format, key, options);
// NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
Q_ASSERT(texture);
if (texture->id > 0)
- const_cast<QPixmap &>(pixmap).data_ptr()->is_cached = true;
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmap);
return texture;
}
@@ -2098,6 +2453,25 @@ int QGLContextPrivate::maxTextureSize()
}
/*!
+ Generates and binds a 2D GL texture to the current context, based
+ on \a image. The generated texture id is returned and can be used in
+ later \c glBindTexture() calls.
+
+ \overload
+*/
+GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
+{
+ if (image.isNull())
+ return 0;
+
+ Q_D(QGLContext);
+ QGLTexture *texture = d->bindTexture(image, target, format, false, DefaultBindOption);
+ return texture->id;
+}
+
+/*!
+ \since 4.6
+
Generates and binds a 2D GL texture to the current context, based
on \a image. The generated texture id is returned and can be used
in later \c glBindTexture() calls.
@@ -2106,12 +2480,10 @@ int QGLContextPrivate::maxTextureSize()
target is \c GL_TEXTURE_2D.
The \a format parameter sets the internal format for the
- texture. The default format is \c GL_RGBA8.
+ texture. The default format is \c GL_RGBA.
- If the GL implementation supports the \c GL_SGIS_generate_mipmap
- extension, mipmaps will be automatically generated for the
- texture. Mipmap generation is only supported for the \c
- GL_TEXTURE_2D target.
+ The binding \a options are a set of options used to decide how to
+ bind the texture to the context.
The texture that is generated is cached, so multiple calls to
bindTexture() with the same QImage will return the same texture
@@ -2122,10 +2494,13 @@ int QGLContextPrivate::maxTextureSize()
\sa deleteTexture()
*/
-GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
+GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format, BindOptions options)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLContext);
- QGLTexture *texture = d->bindTexture(image, target, format, false);
+ QGLTexture *texture = d->bindTexture(image, target, format, false, options);
return texture->id;
}
@@ -2133,8 +2508,23 @@ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
/*! \internal */
GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLContext);
- QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false);
+ QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, DefaultBindOption);
+ return texture->id;
+}
+
+/*! \internal */
+GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format,
+ BindOptions options)
+{
+ if (image.isNull())
+ return 0;
+
+ Q_D(QGLContext);
+ QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false, options);
return texture->id;
}
#endif
@@ -2145,8 +2535,28 @@ GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMa
*/
GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
{
+ if (pixmap.isNull())
+ return 0;
+
Q_D(QGLContext);
- QGLTexture *texture = d->bindTexture(pixmap, target, format, false, false);
+ QGLTexture *texture = d->bindTexture(pixmap, target, format, DefaultBindOption);
+ return texture->id;
+}
+
+/*!
+ \overload
+ \since 4.6
+
+ Generates and binds a 2D GL texture to the current context, based
+ on \a pixmap.
+*/
+GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, BindOptions options)
+{
+ if (pixmap.isNull())
+ return 0;
+
+ Q_D(QGLContext);
+ QGLTexture *texture = d->bindTexture(pixmap, target, format, options);
return texture->id;
}
@@ -2154,8 +2564,22 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint forma
/*! \internal */
GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
{
+ if (pixmap.isNull())
+ return 0;
+
Q_D(QGLContext);
- QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), false, false);
+ QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), DefaultBindOption);
+ return texture->id;
+}
+/*! \internal */
+GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format,
+ BindOptions options)
+{
+ if (pixmap.isNull())
+ return 0;
+
+ Q_D(QGLContext);
+ QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), options);
return texture->id;
}
#endif
@@ -2222,6 +2646,8 @@ void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexT
array[7] = f2vt(y2);
}
+#if !defined(QT_OPENGL_ES_2)
+
static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint textureHeight, GLenum textureTarget)
{
q_vertexType tx = f2vt(1);
@@ -2250,7 +2676,6 @@ static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint tex
q_vertexType vertexArray[4*2];
qt_add_rect_to_array(target, vertexArray);
-#if !defined(QT_OPENGL_ES_2)
glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
@@ -2260,9 +2685,10 @@ static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint tex
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-#endif
}
+#endif // !QT_OPENGL_ES_2
+
/*!
\since 4.4
@@ -2270,10 +2696,11 @@ static void qDrawTextureRect(const QRectF &target, GLint textureWidth, GLint tex
\a target, in OpenGL model space. The \a textureTarget should be a 2D
texture target.
- Equivalent to the corresponding QGLContext::drawTexture().
+ \note This function is not supported under OpenGL/ES 2.0.
*/
void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
{
+#ifndef QT_OPENGL_ES_2
#ifdef QT_OPENGL_ES
if (textureTarget != GL_TEXTURE_2D) {
qWarning("QGLContext::drawTexture(): texture target must be GL_TEXTURE_2D on OpenGL ES");
@@ -2297,6 +2724,12 @@ void QGLContext::drawTexture(const QRectF &target, GLuint textureId, GLenum text
glDisable(textureTarget);
glBindTexture(textureTarget, oldTexture);
#endif
+#else
+ Q_UNUSED(target);
+ Q_UNUSED(textureId);
+ Q_UNUSED(textureTarget);
+ qWarning("drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) not supported with OpenGL ES/2.0");
+#endif
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -2313,7 +2746,7 @@ void QGLContext::drawTexture(const QRectF &target, QMacCompatGLuint textureId, Q
Draws the given texture at the given \a point in OpenGL model
space. The \a textureTarget should be a 2D texture target.
- Equivalent to the corresponding QGLContext::drawTexture().
+ \note This function is not supported under OpenGL/ES.
*/
void QGLContext::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
{
@@ -2455,6 +2888,20 @@ void QGLContext::setDevice(QPaintDevice *pDev)
*/
/*!
+ Returns true if \a context1 and \a context2 are sharing their
+ GL resources such as textures, shader programs, etc;
+ otherwise returns false.
+
+ \since 4.6
+*/
+bool QGLContext::areSharing(const QGLContext *context1, const QGLContext *context2)
+{
+ if (!context1 || !context2)
+ return false;
+ return context1->d_ptr->group == context2->d_ptr->group;
+}
+
+/*!
\fn bool QGLContext::deviceIsPixmap() const
Returns true if the paint device of this context is a pixmap;
@@ -2597,7 +3044,7 @@ void QGLContext::setValid(bool valid)
bool QGLContext::isSharing() const
{
Q_D(const QGLContext);
- return d->sharing;
+ return d->group->isSharing();
}
QGLFormat QGLContext::format() const
@@ -2652,11 +3099,28 @@ void QGLContext::setInitialized(bool on)
const QGLContext* QGLContext::currentContext()
{
- if (qgl_context_storage.hasLocalData())
- return qgl_context_storage.localData()->context;
+ QGLThreadContext *threadContext = qgl_context_storage.localData();
+ if (threadContext)
+ return threadContext->context;
return 0;
}
+void QGLContextPrivate::setCurrentContext(QGLContext *context)
+{
+ QGLThreadContext *threadContext = qgl_context_storage.localData();
+ if (!threadContext) {
+ if (!QThread::currentThread()) {
+ // We don't have a current QThread, so just set the static.
+ QGLContext::currentCtx = context;
+ return;
+ }
+ threadContext = new QGLThreadContext;
+ qgl_context_storage.setLocalData(threadContext);
+ }
+ threadContext->context = context;
+ QGLContext::currentCtx = context; // XXX: backwards-compat, not thread-safe
+}
+
/*!
\fn bool QGLContext::chooseContext(const QGLContext* shareContext = 0)
@@ -2775,8 +3239,8 @@ const QGLContext* QGLContext::currentContext()
\class QGLWidget
\brief The QGLWidget class is a widget for rendering OpenGL graphics.
- \ingroup multimedia
- \mainclass
+ \ingroup painting-3D
+
QGLWidget provides functionality for displaying OpenGL graphics
integrated into a Qt application. It is very simple to use. You
@@ -2817,7 +3281,7 @@ const QGLContext* QGLContext::currentContext()
QGLFormat format\endlink and you can also create widgets with
customized rendering \link QGLContext contexts\endlink.
- You can also share OpenGL display lists between QGLWidgets (see
+ You can also share OpenGL display lists between QGLWidget objects (see
the documentation of the QGLWidget constructors for details).
Note that under Windows, the QGLContext belonging to a QGLWidget
@@ -3099,7 +3563,7 @@ bool QGLWidget::isValid() const
Returns true if this widget's GL context is shared with another GL
context, otherwise false is returned. Context sharing might not be
- possible if the QGLWidgets use different formats.
+ possible if the widgets use different formats.
\sa format()
*/
@@ -3197,7 +3661,7 @@ void QGLWidget::swapBuffers()
resizeGL() or paintGL().
This method will try to keep display list and texture object sharing
- in effect with other QGLWidgets, but changing the format might make
+ in effect with other QGLWidget objects, but changing the format might make
sharing impossible. Use isSharing() to see if sharing is still in
effect.
@@ -3405,25 +3869,28 @@ bool QGLWidget::event(QEvent *e)
glFinish();
doneCurrent();
} else if (e->type() == QEvent::ParentChange) {
+ // if we've reparented a window that has the current context
+ // bound, we need to rebind that context to the new window id
+ if (d->glcx == QGLContext::currentContext())
+ makeCurrent();
+
if (d->glcx->d_func()->screen != d->xinfo.screen() || testAttribute(Qt::WA_TranslucentBackground)) {
setContext(new QGLContext(d->glcx->requestedFormat(), this));
// ### recreating the overlay isn't supported atm
}
+ }
+
#if defined(QT_OPENGL_ES)
- // The window may have been re-created during re-parent - if so, the EGL
+ if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) {
+ // The window may have been re-created during re-parent or state change - if so, the EGL
// surface will need to be re-created.
d->recreateEglSurface(false);
-#endif
}
+#endif
#elif defined(Q_WS_WIN)
if (e->type() == QEvent::ParentChange) {
QGLContext *newContext = new QGLContext(d->glcx->requestedFormat(), this);
- QList<const QGLContext *> shares = qgl_share_reg()->shares(d->glcx);
- setContext(newContext);
- for (int i = 0; i < shares.size(); ++i) {
- if (newContext != shares.at(i))
- qgl_share_reg()->addShare(newContext, shares.at(i));
- }
+ setContext(newContext, d->glcx);
// the overlay needs to be recreated as well
delete d->olcx;
@@ -3503,7 +3970,7 @@ void QGLWidget::paintEvent(QPaintEvent *)
/*!
Renders the current scene on a pixmap and returns the pixmap.
- You can use this method on both visible and invisible QGLWidgets.
+ You can use this method on both visible and invisible QGLWidget objects.
This method will create a pixmap and a temporary QGLContext to
render on the pixmap. It will then call initializeGL(),
@@ -3625,7 +4092,7 @@ QImage QGLWidget::grabFrameBuffer(bool withAlpha)
glReadPixels(0, 0, w, h, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, res.bits());
const QVector<QColor> pal = QColormap::instance().colormap();
if (pal.size()) {
- res.setNumColors(pal.size());
+ res.setColorCount(pal.size());
for (int i = 0; i < pal.size(); i++)
res.setColor(i, pal.at(i).rgb());
}
@@ -3689,6 +4156,8 @@ void QGLWidget::glDraw()
Calls glColor4 (in RGBA mode) or glIndex (in color-index mode)
with the color \a c. Applies to this widgets GL context.
+ \note This function is not supported on OpenGL/ES 2.0 systems.
+
\sa qglClearColor(), QGLContext::currentContext(), QColor
*/
@@ -3696,7 +4165,7 @@ void QGLWidget::qglColor(const QColor& c) const
{
#if !defined(QT_OPENGL_ES_2)
#ifdef QT_OPENGL_ES
- glColor4f(c.red()/255.0, c.green()/255.0, c.blue()/255.0, c.alpha()/255.0);
+ glColor4f(c.redF(), c.greenF(), c.blueF(), c.alphaF());
#else
Q_D(const QGLWidget);
const QGLContext *ctx = QGLContext::currentContext();
@@ -3712,6 +4181,8 @@ void QGLWidget::qglColor(const QColor& c) const
glIndexi(ctx->colorIndex(c));
}
#endif //QT_OPENGL_ES
+#else
+ Q_UNUSED(c);
#endif //QT_OPENGL_ES_2
}
@@ -3726,15 +4197,13 @@ void QGLWidget::qglColor(const QColor& c) const
void QGLWidget::qglClearColor(const QColor& c) const
{
#ifdef QT_OPENGL_ES
- glClearColor((GLfloat)c.red() / 255.0, (GLfloat)c.green() / 255.0,
- (GLfloat)c.blue() / 255.0, (GLfloat) c.alpha() / 255.0);
+ glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
#else
Q_D(const QGLWidget);
const QGLContext *ctx = QGLContext::currentContext();
if (ctx) {
if (ctx->format().rgba())
- glClearColor((GLfloat)c.red() / 255.0, (GLfloat)c.green() / 255.0,
- (GLfloat)c.blue() / 255.0, (GLfloat) c.alpha() / 255.0);
+ glClearColor(c.redF(), c.greenF(), c.blueF(), c.alphaF());
else if (!d->cmap.isEmpty()) { // QGLColormap in use?
int i = d->cmap.find(c.rgb());
if (i < 0)
@@ -3805,10 +4274,10 @@ QImage QGLWidget::convertToGLFormat(const QImage& img)
colormaps installed. Asking for the colormap of a child widget
will return the colormap for the child's top-level widget.
- If no colormap has been set for this widget, the QColormap
+ If no colormap has been set for this widget, the QGLColormap
returned will be empty.
- \sa setColormap()
+ \sa setColormap(), QGLColormap::isEmpty()
*/
/*!
@@ -3828,9 +4297,12 @@ QImage QGLWidget::convertToGLFormat(const QImage& img)
the characters in the given \a font. \a listBase indicates the base
value used when generating the display lists for the font. The
default value is 2000.
+
+ \note This function is not supported on OpenGL/ES systems.
*/
int QGLWidget::fontDisplayListBase(const QFont & font, int listBase)
{
+#ifndef QT_OPENGL_ES
Q_D(QGLWidget);
int base;
@@ -3848,9 +4320,7 @@ int QGLWidget::fontDisplayListBase(const QFont & font, int listBase)
QString color_key;
if (font.styleStrategy() != QFont::NoAntialias) {
GLfloat color[4];
-#ifndef QT_OPENGL_ES
glGetFloatv(GL_CURRENT_COLOR, color);
-#endif
color_key.sprintf("%f_%f_%f",color[0], color[1], color[2]);
}
QString key = font.key() + color_key + QString::number((int) regenerate);
@@ -3873,15 +4343,19 @@ int QGLWidget::fontDisplayListBase(const QFont & font, int listBase)
base = maxBase;
}
return base;
+#else // QT_OPENGL_ES
+ Q_UNUSED(font);
+ Q_UNUSED(listBase);
+ return 0;
+#endif
}
+#ifndef QT_OPENGL_ES
+
static void qt_save_gl_state()
{
-#ifndef QT_OPENGL_ES
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
glPushAttrib(GL_ALL_ATTRIB_BITS);
-#endif
-#if !defined(QT_OPENGL_ES_2)
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
@@ -3896,32 +4370,25 @@ static void qt_save_gl_state()
glDisable(GL_STENCIL_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-#endif // !defined(QT_OPENGL_ES_2)
}
static void qt_restore_gl_state()
{
-#if !defined(QT_OPENGL_ES_2)
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
-#endif // !defined(QT_OPENGL_ES_2)
-#ifndef QT_OPENGL_ES
glPopAttrib();
glPopClientAttrib();
-#endif
}
static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str,
const QFont &font)
{
GLfloat color[4];
-#ifndef QT_OPENGL_ES
glGetFloatv(GL_CURRENT_COLOR, &color[0]);
-#endif
QColor col;
col.setRgbF(color[0], color[1], color[2],color[3]);
@@ -3936,6 +4403,8 @@ static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str,
p->setFont(old_font);
}
+#endif // !QT_OPENGL_ES
+
/*!
Renders the string \a str into the GL context of this widget.
@@ -3950,27 +4419,29 @@ static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str,
future version of Qt.
\note This function clears the stencil buffer.
+
+ \note This function is not supported on OpenGL/ES systems.
+ \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead.
*/
void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, int)
{
+#ifndef QT_OPENGL_ES
Q_D(QGLWidget);
if (str.isEmpty() || !isValid())
return;
GLint view[4];
-#ifndef QT_OPENGL_ES
bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST);
if (!use_scissor_testing)
glGetIntegerv(GL_VIEWPORT, &view[0]);
-#else
- bool use_scissor_testing = false;
-#endif
int width = d->glcx->device()->width();
int height = d->glcx->device()->height();
bool auto_swap = autoBufferSwap();
QPaintEngine *engine = paintEngine();
+ if (engine->type() == QPaintEngine::OpenGL2)
+ static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
QPainter *p;
bool reuse_painter = false;
if (engine->isActive()) {
@@ -3978,24 +4449,23 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
p = engine->painter();
qt_save_gl_state();
-#if !defined(QT_OPENGL_ES_2)
glDisable(GL_DEPTH_TEST);
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
-#ifndef QT_OPENGL_ES
glOrtho(0, width, height, 0, 0, 1);
-#else
- glOrthof(0, width, height, 0, 0, 1);
-#endif
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
-#endif // !defined(QT_OPENGL_ES_2)
} else {
setAutoBufferSwap(false);
// disable glClear() as a result of QPainter::begin()
- d->glcx->d_func()->clear_on_painter_begin = false;
+ d->disable_clear_on_painter_begin = true;
+ if (engine->type() == QPaintEngine::OpenGL2) {
+ qt_save_gl_state();
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ }
p = new QPainter(this);
}
@@ -4018,8 +4488,19 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
p->end();
delete p;
setAutoBufferSwap(auto_swap);
- d->glcx->d_func()->clear_on_painter_begin = true;
+ d->disable_clear_on_painter_begin = false;
+ if (engine->type() == QPaintEngine::OpenGL2)
+ qt_restore_gl_state();
}
+ if (engine->type() == QPaintEngine::OpenGL2)
+ static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+#else // QT_OPENGL_ES
+ Q_UNUSED(x);
+ Q_UNUSED(y);
+ Q_UNUSED(str);
+ Q_UNUSED(font);
+ qWarning("QGLWidget::renderText is not supported under OpenGL/ES");
+#endif
}
/*! \overload
@@ -4028,9 +4509,13 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
relative to the currently set projection and model matrices. This
can be useful if you want to annotate models with text labels and
have the labels move with the model as it is rotated etc.
+
+ \note This function is not supported on OpenGL/ES systems.
+ \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead.
*/
void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int)
{
+#ifndef QT_OPENGL_ES
Q_D(QGLWidget);
if (str.isEmpty() || !isValid())
return;
@@ -4041,26 +4526,21 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
int height = d->glcx->device()->height();
GLdouble model[4][4], proj[4][4];
GLint view[4];
-#ifndef QT_OPENGL_ES
glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]);
glGetIntegerv(GL_VIEWPORT, &view[0]);
-#endif
GLdouble win_x = 0, win_y = 0, win_z = 0;
qgluProject(x, y, z, &model[0][0], &proj[0][0], &view[0],
&win_x, &win_y, &win_z);
win_y = height - win_y; // y is inverted
QPaintEngine *engine = paintEngine();
+ if (engine->type() == QPaintEngine::OpenGL2)
+ static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
QPainter *p;
bool reuse_painter = false;
-#ifndef QT_OPENGL_ES
bool use_depth_testing = glIsEnabled(GL_DEPTH_TEST);
bool use_scissor_testing = glIsEnabled(GL_SCISSOR_TEST);
-#else
- bool use_depth_testing = false;
- bool use_scissor_testing = false;
-#endif
if (engine->isActive()) {
reuse_painter = true;
@@ -4069,7 +4549,9 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
} else {
setAutoBufferSwap(false);
// disable glClear() as a result of QPainter::begin()
- d->glcx->d_func()->clear_on_painter_begin = false;
+ d->disable_clear_on_painter_begin = true;
+ if (engine->type() == QPaintEngine::OpenGL2)
+ qt_save_gl_state();
p = new QPainter(this);
}
@@ -4080,27 +4562,17 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
} else if (use_scissor_testing) {
glEnable(GL_SCISSOR_TEST);
}
-#if !defined(QT_OPENGL_ES_2)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, width, height);
-#ifndef QT_OPENGL_ES
glOrtho(0, width, height, 0, 0, 1);
-#else
- glOrthof(0, width, height, 0, 0, 1);
-#endif
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glAlphaFunc(GL_GREATER, 0.0);
glEnable(GL_ALPHA_TEST);
if (use_depth_testing)
glEnable(GL_DEPTH_TEST);
-#ifndef QT_OPENGL_ES
glTranslated(0, 0, -win_z);
-#else
- glTranslatef(0, 0, -win_z);
-#endif
-#endif // !defined(QT_OPENGL_ES_2)
qt_gl_draw_text(p, qRound(win_x), qRound(win_y), str, font);
if (reuse_painter) {
@@ -4108,9 +4580,21 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
} else {
p->end();
delete p;
+ if (engine->type() == QPaintEngine::OpenGL2)
+ qt_restore_gl_state();
setAutoBufferSwap(auto_swap);
- d->glcx->d_func()->clear_on_painter_begin = true;
+ d->disable_clear_on_painter_begin = false;
}
+ if (engine->type() == QPaintEngine::OpenGL2)
+ static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+#else // QT_OPENGL_ES
+ Q_UNUSED(x);
+ Q_UNUSED(y);
+ Q_UNUSED(z);
+ Q_UNUSED(str);
+ Q_UNUSED(font);
+ qWarning("QGLWidget::renderText is not supported under OpenGL/ES");
+#endif
}
QGLFormat QGLWidget::format() const
@@ -4151,16 +4635,49 @@ bool QGLWidget::autoBufferSwap() const
*/
GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format)
{
+ if (image.isNull())
+ return 0;
+
+ Q_D(QGLWidget);
+ return d->glcx->bindTexture(image, target, format, QGLContext::DefaultBindOption);
+}
+
+/*!
+ \overload
+ \since 4.6
+
+ The binding \a options are a set of options used to decide how to
+ bind the texture to the context.
+ */
+GLuint QGLWidget::bindTexture(const QImage &image, GLenum target, GLint format, QGLContext::BindOptions options)
+{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLWidget);
- return d->glcx->bindTexture(image, target, format);
+ return d->glcx->bindTexture(image, target, format, options);
}
+
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
/*! \internal */
GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
{
+ if (image.isNull())
+ return 0;
+
Q_D(QGLWidget);
- return d->glcx->bindTexture(image, GLenum(target), GLint(format));
+ return d->glcx->bindTexture(image, GLenum(target), GLint(format), QGLContext::DefaultBindOption);
+}
+
+GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format,
+ QGLContext::BindOptions options)
+{
+ if (image.isNull())
+ return 0;
+
+ Q_D(QGLWidget);
+ return d->glcx->bindTexture(image, GLenum(target), GLint(format), options);
}
#endif
@@ -4172,8 +4689,28 @@ GLuint QGLWidget::bindTexture(const QImage &image, QMacCompatGLenum target, QMac
*/
GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
{
+ if (pixmap.isNull())
+ return 0;
+
+ Q_D(QGLWidget);
+ return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption);
+}
+
+/*!
+ \overload
+ \since 4.6
+
+ Generates and binds a 2D GL texture to the current context, based
+ on \a pixmap. The generated texture id is returned and can be used in
+
+ The binding \a options are a set of options used to decide how to
+ bind the texture to the context.
+ */
+GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
+ QGLContext::BindOptions options)
+{
Q_D(QGLWidget);
- return d->glcx->bindTexture(pixmap, target, format);
+ return d->glcx->bindTexture(pixmap, target, format, options);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -4181,7 +4718,14 @@ GLuint QGLWidget::bindTexture(const QPixmap &pixmap, GLenum target, GLint format
GLuint QGLWidget::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
{
Q_D(QGLWidget);
- return d->glcx->bindTexture(pixmap, target, format);
+ return d->glcx->bindTexture(pixmap, target, format, QGLContext::DefaultBindOption);
+}
+
+GLuint QGLWidget::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format,
+ QGLContext::BindOptions options)
+{
+ Q_D(QGLWidget);
+ return d->glcx->bindTexture(pixmap, target, format, options);
}
#endif
@@ -4274,16 +4818,19 @@ Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_2_engine)
Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_engine)
#endif
-#ifdef Q_WS_QWS
Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine()
{
-#if !defined(QT_OPENGL_ES_2)
+#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)
return qt_gl_engine();
+#elif defined(QT_OPENGL_ES_2)
+ return qt_gl_2_engine();
#else
- return 0; // XXX
+ if (qt_gl_preferGL2Engine())
+ return qt_gl_2_engine();
+ else
+ return qt_gl_engine();
#endif
}
-#endif
/*!
\internal
@@ -4293,16 +4840,7 @@ Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine()
*/
QPaintEngine *QGLWidget::paintEngine() const
{
-#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)
- return qt_gl_engine();
-#elif defined(QT_OPENGL_ES_2)
- return qt_gl_2_engine();
-#else
- if (!qt_gl_preferGL2Engine())
- return qt_gl_engine();
- else
- return qt_gl_2_engine();
-#endif
+ return qt_qgl_paint_engine();
}
#ifdef QT3_SUPPORT
@@ -4362,41 +4900,59 @@ QGLWidget::QGLWidget(QGLContext *context, QWidget *parent,
void QGLExtensions::init_extensions()
{
- QString extensions = QLatin1String(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)));
- if (extensions.contains(QLatin1String("texture_rectangle")))
+ QList<QByteArray> extensions = QByteArray(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))).split(' ');
+ if (extensions.contains("GL_ARB_texture_rectangle"))
glExtensions |= TextureRectangle;
- if (extensions.contains(QLatin1String("multisample")))
+ if (extensions.contains("GL_ARB_multisample"))
glExtensions |= SampleBuffers;
- if (extensions.contains(QLatin1String("generate_mipmap")))
+ if (extensions.contains("GL_SGIS_generate_mipmap"))
glExtensions |= GenerateMipmap;
- if (extensions.contains(QLatin1String("texture_compression_s3tc")))
+ if (extensions.contains("GL_EXT_texture_compression_s3tc"))
glExtensions |= TextureCompression;
- if (extensions.contains(QLatin1String("ARB_fragment_program")))
+ if (extensions.contains("GL_ARB_fragment_program"))
glExtensions |= FragmentProgram;
- if (extensions.contains(QLatin1String("mirrored_repeat")))
+ if (extensions.contains("GL_ARB_texture_mirrored_repeat"))
glExtensions |= MirroredRepeat;
- if (extensions.contains(QLatin1String("EXT_framebuffer_object")))
+ if (extensions.contains("GL_EXT_framebuffer_object"))
glExtensions |= FramebufferObject;
- if (extensions.contains(QLatin1String("EXT_stencil_two_side")))
+ if (extensions.contains("GL_EXT_stencil_two_side"))
glExtensions |= StencilTwoSide;
- if (extensions.contains(QLatin1String("EXT_stencil_wrap")))
+ if (extensions.contains("GL_EXT_stencil_wrap"))
glExtensions |= StencilWrap;
- if (extensions.contains(QLatin1String("EXT_packed_depth_stencil")))
+ if (extensions.contains("GL_EXT_packed_depth_stencil"))
glExtensions |= PackedDepthStencil;
- if (extensions.contains(QLatin1String("GL_NV_float_buffer")))
+ if (extensions.contains("GL_NV_float_buffer"))
glExtensions |= NVFloatBuffer;
- if (extensions.contains(QLatin1String("ARB_pixel_buffer_object")))
+ if (extensions.contains("GL_ARB_pixel_buffer_object"))
glExtensions |= PixelBufferObject;
#if defined(QT_OPENGL_ES_2)
glExtensions |= FramebufferObject;
glExtensions |= GenerateMipmap;
#endif
- if (extensions.contains(QLatin1String("EXT_framebuffer_blit")))
+#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)
+ if (extensions.contains("GL_OES_framebuffer_object"))
+ glExtensions |= FramebufferObject;
+#endif
+#if defined(QT_OPENGL_ES)
+ if (extensions.contains("GL_OES_packed_depth_stencil"))
+ glExtensions |= PackedDepthStencil;
+#endif
+ if (extensions.contains("GL_ARB_framebuffer_object")) {
+ // ARB_framebuffer_object also includes EXT_framebuffer_blit.
+ glExtensions |= FramebufferObject;
+ glExtensions |= FramebufferBlit;
+ }
+
+ if (extensions.contains("GL_EXT_framebuffer_blit"))
glExtensions |= FramebufferBlit;
- if (extensions.contains(QLatin1String("GL_ARB_texture_non_power_of_two")))
+ if (extensions.contains("GL_ARB_texture_non_power_of_two"))
glExtensions |= NPOTTextures;
+ if (extensions.contains("GL_EXT_bgra"))
+ glExtensions |= BGRATextureFormat;
+
+
QGLContext cx(QGLFormat::defaultFormat());
if (glExtensions & TextureCompression) {
qt_glCompressedTexImage2DARB = (pfn_glCompressedTexImage2DARB) cx.getProcAddress(QLatin1String("glCompressedTexImage2DARB"));
@@ -4410,6 +4966,8 @@ void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWi
{
Q_Q(QGLWidget);
+ glDevice.setWidget(q);
+
QGLExtensions::init();
glcx = 0;
autoSwap = true;
@@ -4445,389 +5003,113 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name()
}
#endif
-void QGLDrawable::setDevice(QPaintDevice *pdev)
-{
- wasBound = false;
- widget = 0;
- buffer = 0;
- fbo = 0;
-#ifdef Q_WS_QWS
- wsurf = 0;
-#endif
-
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- if (pdev->devType() == QInternal::Pixmap) {
- QPixmapData *data = static_cast<QPixmap *>(pdev)->pixmapData();
- Q_ASSERT(data->classId() == QPixmapData::OpenGLClass);
- pixmapData = static_cast<QGLPixmapData *>(data);
-
- fbo = pixmapData->fbo();
- }
-#else
- Q_ASSERT(pdev->devType() != QInternal::Pixmap);
-#endif
-
- if (pdev->devType() == QInternal::Widget)
- widget = static_cast<QGLWidget *>(pdev);
- else if (pdev->devType() == QInternal::Pbuffer)
- buffer = static_cast<QGLPixelBuffer *>(pdev);
- else if (pdev->devType() == QInternal::FramebufferObject)
- fbo = static_cast<QGLFramebufferObject *>(pdev);
-#ifdef Q_WS_QWS
- else if (pdev->devType() == QInternal::UnknownDevice)
- wsurf = static_cast<QWSGLPaintDevice*>(pdev)->windowSurface();
-#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- else if (pdev->devType() == QInternal::UnknownDevice)
- wsurf = static_cast<QGLWindowSurface *>(pdev);
-#endif
-}
-
-void QGLDrawable::swapBuffers()
-{
- if (widget) {
- if (widget->autoBufferSwap())
- widget->swapBuffers();
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- } else if (pixmapData) {
- pixmapData->swapBuffers();
-#endif
- } else {
- glFlush();
- }
-}
-
-void QGLDrawable::makeCurrent()
-{
- previous_fbo = 0;
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- if (!pixmapData && !fbo) {
-#else
- if (!fbo) {
-#endif
- QGLContext *ctx = context();
- previous_fbo = ctx->d_ptr->current_fbo;
- ctx->d_ptr->current_fbo = 0;
- if (previous_fbo)
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
- }
-
- if (widget)
- widget->makeCurrent();
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- else if (pixmapData)
- pixmapData->makeCurrent();
-#endif
- else if (buffer)
- buffer->makeCurrent();
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- else if (wsurf)
- wsurf->context()->makeCurrent();
-#endif
- else if (fbo) {
- wasBound = fbo->isBound();
- if (!wasBound)
- fbo->bind();
- }
-}
-
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
-QGLPixmapData *QGLDrawable::copyOnBegin() const
-{
- if (!pixmapData || pixmapData->isUninitialized())
- return 0;
- return pixmapData;
-}
-#endif
-
-void QGLDrawable::doneCurrent()
-{
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- if (pixmapData) {
- pixmapData->doneCurrent();
- return;
- }
-#endif
-
- if (previous_fbo) {
- QGLContext *ctx = context();
- ctx->d_ptr->current_fbo = previous_fbo;
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, previous_fbo);
- }
-
- if (fbo && !wasBound)
- fbo->release();
-}
-
-QSize QGLDrawable::size() const
-{
- if (widget) {
- return QSize(widget->d_func()->glcx->device()->width(),
- widget->d_func()->glcx->device()->height());
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- } else if (pixmapData) {
- return pixmapData->size();
-#endif
- } else if (buffer) {
- return buffer->size();
- } else if (fbo) {
- return fbo->size();
- }
-#ifdef Q_WS_QWS
- else if (wsurf)
- return wsurf->window()->frameSize();
-#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- else if (wsurf)
- return QSize(wsurf->width(), wsurf->height());
-#endif
- return QSize();
-}
-
-QGLFormat QGLDrawable::format() const
-{
- if (widget)
- return widget->format();
- else if (buffer)
- return buffer->format();
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- else if (wsurf)
- return wsurf->context()->format();
-#endif
- else if (fbo && QGLContext::currentContext()) {
- QGLFormat fmt = QGLContext::currentContext()->format();
- fmt.setStencil(fbo->attachment() == QGLFramebufferObject::CombinedDepthStencil);
- fmt.setDepth(fbo->attachment() != QGLFramebufferObject::NoAttachment);
- return fmt;
- }
-
- return QGLFormat();
-}
-
-GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format)
-{
- QGLTexture *texture = 0;
- if (widget)
- texture = widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true);
- else if (buffer)
- texture = buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true);
- else if (fbo && QGLContext::currentContext())
- texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true);
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- else if (wsurf)
- texture = wsurf->context()->d_func()->bindTexture(image, target, format, true);
-#endif
- return texture->id;
-}
-
-GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
-{
- QGLTexture *texture = 0;
- if (widget)
- texture = widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true, true);
- else if (buffer)
- texture = buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true, true);
- else if (fbo && QGLContext::currentContext())
- texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true, true);
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- else if (wsurf)
- texture = wsurf->context()->d_func()->bindTexture(pixmap, target, format, true, true);
-#endif
- return texture->id;
-}
-
-QColor QGLDrawable::backgroundColor() const
-{
- if (widget)
- return widget->palette().brush(widget->backgroundRole()).color();
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- else if (pixmapData)
- return pixmapData->fillColor();
-#endif
- return QApplication::palette().brush(QPalette::Background).color();
-}
-
-bool QGLDrawable::hasTransparentBackground() const
-{
- return widget && widget->testAttribute(Qt::WA_TranslucentBackground);
-}
-
-QGLContext *QGLDrawable::context() const
-{
- if (widget)
- return widget->d_func()->glcx;
- else if (buffer)
- return buffer->d_func()->qctx;
- else if (fbo)
- return const_cast<QGLContext *>(QGLContext::currentContext());
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- else if (wsurf)
- return wsurf->context();
-#endif
- return 0;
-}
-
-bool QGLDrawable::autoFillBackground() const
-{
- if (widget)
- return widget->autoFillBackground();
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- else if (pixmapData)
- return pixmapData->needsFill();
-#endif
- else
- return false;
-}
-
-
-bool QGLShareRegister::checkSharing(const QGLContext *context1, const QGLContext *context2) {
- bool sharing = (context1 && context2 && context1->d_ptr->groupResources == context2->d_ptr->groupResources);
- return sharing;
-}
-
void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) {
Q_ASSERT(context && share);
- if (context->d_ptr->groupResources == share->d_ptr->groupResources)
+ if (context->d_ptr->group == share->d_ptr->group)
return;
// Make sure 'context' is not already shared with another group of contexts.
- Q_ASSERT(reg.find(context->d_ptr->groupResources) == reg.end());
- Q_ASSERT(context->d_ptr->groupResources->refs == 1);
+ Q_ASSERT(context->d_ptr->group->m_refs == 1);
// Free 'context' group resources and make it use the same resources as 'share'.
- delete context->d_ptr->groupResources;
- context->d_ptr->groupResources = share->d_ptr->groupResources;
- context->d_ptr->groupResources->refs.ref();
+ QGLContextGroup *group = share->d_ptr->group;
+ delete context->d_ptr->group;
+ context->d_ptr->group = group;
+ group->m_refs.ref();
// Maintain a list of all the contexts in each group of sharing contexts.
- SharingHash::iterator it = reg.find(share->d_ptr->groupResources);
- if (it == reg.end())
- it = reg.insert(share->d_ptr->groupResources, ContextList() << share);
- it.value() << context;
+ // The list is empty if the "share" context wasn't sharing already.
+ if (group->m_shares.isEmpty())
+ group->m_shares.append(share);
+ group->m_shares.append(context);
}
QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) {
- SharingHash::const_iterator it = reg.find(context->d_ptr->groupResources);
- if (it == reg.end())
- return ContextList();
- return it.value();
+ return context->d_ptr->group->m_shares;
}
void QGLShareRegister::removeShare(const QGLContext *context) {
- SharingHash::iterator it = reg.find(context->d_ptr->groupResources);
- if (it == reg.end())
+ // Remove the context from the group.
+ QGLContextGroup *group = context->d_ptr->group;
+ if (group->m_shares.isEmpty())
return;
+ group->m_shares.removeAll(context);
- int count = it.value().removeAll(context);
- Q_ASSERT(count == 1);
- Q_UNUSED(count);
+ // Update context group representative.
+ Q_ASSERT(group->m_shares.size() != 0);
+ if (group->m_context == context)
+ group->m_context = group->m_shares[0];
- Q_ASSERT(it.value().size() != 0);
- if (it.value().size() == 1)
- reg.erase(it);
+ // If there is only one context left, then make the list empty.
+ if (group->m_shares.size() == 1)
+ group->m_shares.clear();
}
-QGLContextResource::QGLContextResource(FreeFunc f, QObject *parent)
- : QObject(parent), free(f)
+QGLContextResource::QGLContextResource(FreeFunc f)
+ : free(f), active(0)
{
- connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)), this, SLOT(aboutToDestroyContext(const QGLContext *)));
}
QGLContextResource::~QGLContextResource()
{
- while (!m_resources.empty())
- remove(m_resources.begin().key());
+#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.");
+ }
+#endif
}
void QGLContextResource::insert(const QGLContext *key, void *value)
{
- QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
- if (shares.size() == 0)
- shares.append(key);
- void *oldValue = 0;
- for (int i = 0; i < shares.size(); ++i) {
- ResourceHash::iterator it = m_resources.find(shares.at(i));
- if (it != m_resources.end()) {
- Q_ASSERT(oldValue == 0 || oldValue == it.value());
- oldValue = it.value();
- it.value() = value;
- } else {
- m_resources.insert(shares.at(i), value);
- }
- }
- if (oldValue != 0 && oldValue != value) {
- QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
- if (oldContext != key)
- const_cast<QGLContext *>(key)->makeCurrent();
- free(oldValue);
- if (oldContext && oldContext != key)
- oldContext->makeCurrent();
- }
+ QGLContextGroup *group = QGLContextPrivate::contextGroup(key);
+ Q_ASSERT(!group->m_resources.contains(this));
+ group->m_resources.insert(this, value);
+ active.ref();
}
void *QGLContextResource::value(const QGLContext *key)
{
- ResourceHash::const_iterator it = m_resources.find(key);
- // Check if there is a value associated with 'key'.
- if (it != m_resources.end())
- return it.value();
- // Check if there is a value associated with sharing contexts.
- QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
- for (int i = 0; i < shares.size() && it == m_resources.end(); ++i)
- it = m_resources.find(shares.at(i));
- if (it == m_resources.end())
- return 0; // Didn't find anything.
-
- // Found something! Share this info with all the buddies.
- for (int i = 0; i < shares.size(); ++i)
- m_resources.insert(shares.at(i), it.value());
- return it.value();
-}
-
-void QGLContextResource::remove(const QGLContext *key)
-{
- QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
- if (shares.size() == 0)
- shares.append(key);
- void *oldValue = 0;
- for (int i = 0; i < shares.size(); ++i) {
- ResourceHash::iterator it = m_resources.find(shares.at(i));
- if (it != m_resources.end()) {
- Q_ASSERT(oldValue == 0 || oldValue == it.value());
- oldValue = it.value();
- m_resources.erase(it);
- }
- }
- if (oldValue != 0) {
- QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
- if (oldContext != key)
- const_cast<QGLContext *>(key)->makeCurrent();
- free(oldValue);
- if (oldContext && oldContext != key)
- oldContext->makeCurrent();
- }
+ QGLContextGroup *group = QGLContextPrivate::contextGroup(key);
+ return group->m_resources.value(this, 0);
}
-void QGLContextResource::aboutToDestroyContext(const QGLContext *key)
+void QGLContextResource::cleanup(const QGLContext *ctx, void *value)
{
- ResourceHash::iterator it = m_resources.find(key);
- if (it == m_resources.end())
+ QGLShareContextScope scope(ctx);
+ free(value);
+ active.deref();
+}
+
+void QGLContextGroup::cleanupResources(const QGLContext *ctx)
+{
+ // If there are still shares, then no cleanup to be done yet.
+ if (m_shares.size() > 1)
return;
- QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
- if (shares.size() > 1) {
- Q_ASSERT(key->isSharing());
- // At least one of the shared contexts must stay in the cache.
- // Otherwise, the value pointer is lost.
- for (int i = 0; i < 2/*shares.size()*/; ++i)
- m_resources.insert(shares.at(i), it.value());
+ // Iterate over all resources and free each in turn.
+ QHash<QGLContextResource *, void *>::ConstIterator it;
+ for (it = m_resources.begin(); it != m_resources.end(); ++it)
+ it.key()->cleanup(ctx, it.value());
+}
+
+QGLSharedResourceGuard::~QGLSharedResourceGuard()
+{
+ if (m_group)
+ m_group->removeGuard(this);
+}
+
+void QGLSharedResourceGuard::setContext(const QGLContext *context)
+{
+ if (m_group)
+ m_group->removeGuard(this);
+ if (context) {
+ m_group = QGLContextPrivate::contextGroup(context);
+ m_group->addGuard(this);
} else {
- QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
- if (oldContext != key)
- const_cast<QGLContext *>(key)->makeCurrent();
- free(it.value());
- if (oldContext && oldContext != key)
- oldContext->makeCurrent();
+ m_group = 0;
}
- m_resources.erase(it);
}
QT_END_NAMESPACE
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index c15a39ecd..079953f31 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -43,8 +43,10 @@
#define QGL_H
#include <QtGui/qwidget.h>
+#include <QtGui/qpaintengine.h>
#include <QtOpenGL/qglcolormap.h>
#include <QtCore/qmap.h>
+#include <QtCore/qscopedpointer.h>
QT_BEGIN_HEADER
@@ -129,6 +131,8 @@ class QGLContextPrivate;
// Namespace class:
namespace QGL
{
+ Q_OPENGL_EXPORT void setPreferredPaintEngine(QPaintEngine::Type engineType);
+
enum FormatOption {
DoubleBuffer = 0x0001,
DepthBuffer = 0x0002,
@@ -254,6 +258,8 @@ public:
private:
QGLFormatPrivate *d;
+ void detach();
+
friend Q_OPENGL_EXPORT bool operator==(const QGLFormat&, const QGLFormat&);
friend Q_OPENGL_EXPORT bool operator!=(const QGLFormat&, const QGLFormat&);
};
@@ -276,7 +282,8 @@ public:
bool isSharing() const;
void reset();
- // ### Qt 5: make format() return a const ref instead
+ static bool areSharing(const QGLContext *context1, const QGLContext *context2);
+
QGLFormat format() const;
QGLFormat requestedFormat() const;
void setFormat(const QGLFormat& format);
@@ -287,6 +294,29 @@ public:
virtual void swapBuffers() const;
+ enum BindOption {
+ NoBindOption = 0x0000,
+ InvertedYBindOption = 0x0001,
+ MipmapBindOption = 0x0002,
+ PremultipliedAlphaBindOption = 0x0004,
+ LinearFilteringBindOption = 0x0008,
+
+ MemoryManagedBindOption = 0x0010, // internal flag
+ CanFlipNativePixmapBindOption = 0x0020, // internal flag
+
+ DefaultBindOption = LinearFilteringBindOption
+ | InvertedYBindOption
+ | MipmapBindOption,
+ InternalBindOption = MemoryManagedBindOption
+ | PremultipliedAlphaBindOption
+ };
+ Q_DECLARE_FLAGS(BindOptions, BindOption)
+
+ GLuint bindTexture(const QImage &image, GLenum target, GLint format,
+ BindOptions options);
+ GLuint bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
+ BindOptions options);
+
GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D,
GLint format = GL_RGBA);
GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D,
@@ -303,6 +333,10 @@ public:
QMacCompatGLint format = GL_RGBA);
GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum = GL_TEXTURE_2D,
QMacCompatGLint format = GL_RGBA);
+ GLuint bindTexture(const QImage &image, QMacCompatGLenum, QMacCompatGLint format,
+ BindOptions);
+ GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum, QMacCompatGLint format,
+ BindOptions);
void deleteTexture(QMacCompatGLuint tx_id);
@@ -348,12 +382,11 @@ protected:
static QGLContext* currentCtx;
private:
- QGLContextPrivate* d_ptr;
+ QScopedPointer<QGLContextPrivate> d_ptr;
friend class QGLPixelBuffer;
friend class QGLPixelBufferPrivate;
friend class QGLWidget;
- friend class QGLDrawable;
friend class QGLWidgetPrivate;
friend class QGLGlyphCache;
friend class QOpenGLPaintEngine;
@@ -365,6 +398,8 @@ private:
friend class QGLPixmapFilterBase;
friend class QGLTextureGlyphCache;
friend class QGLShareRegister;
+ friend class QGLSharedResourceGuard;
+ friend class QGLPixmapBlurFilter;
friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags();
#ifdef Q_WS_MAC
public:
@@ -375,14 +410,14 @@ private:
#endif
friend class QGLFramebufferObject;
friend class QGLFramebufferObjectPrivate;
-#ifdef Q_WS_WIN
- friend bool qt_resolve_GLSL_functions(QGLContext *ctx);
- friend bool qt_createGLSLProgram(QGLContext *ctx, GLuint &program, const char *shader_src, GLuint &shader);
-#endif
+ friend class QGLFBOGLPaintDevice;
+ friend class QGLPaintDevice;
+ friend class QX11GLPixmapData;
private:
Q_DISABLE_COPY(QGLContext)
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGLContext::BindOptions)
class Q_OPENGL_EXPORT QGLWidget : public QWidget
{
@@ -418,7 +453,6 @@ public:
bool doubleBuffer() const;
void swapBuffers();
- // ### Qt 5: make format() return a const ref instead
QGLFormat format() const;
void setFormat(const QGLFormat& format);
@@ -445,10 +479,16 @@ public:
const QFont & fnt = QFont(), int listBase = 2000);
QPaintEngine *paintEngine() const;
+ GLuint bindTexture(const QImage &image, GLenum target, GLint format,
+ QGLContext::BindOptions options);
+ GLuint bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
+ QGLContext::BindOptions options);
+
GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D,
GLint format = GL_RGBA);
GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D,
GLint format = GL_RGBA);
+
GLuint bindTexture(const QString &fileName);
void deleteTexture(GLuint tx_id);
@@ -461,6 +501,10 @@ public:
QMacCompatGLint format = GL_RGBA);
GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum = GL_TEXTURE_2D,
QMacCompatGLint format = GL_RGBA);
+ GLuint bindTexture(const QImage &image, QMacCompatGLenum, QMacCompatGLint format,
+ QGLContext::BindOptions);
+ GLuint bindTexture(const QPixmap &pixmap, QMacCompatGLenum, QMacCompatGLint format,
+ QGLContext::BindOptions);
void deleteTexture(QMacCompatGLuint tx_id);
@@ -504,6 +548,8 @@ private:
friend class QGLContext;
friend class QGLOverlayWidget;
friend class QOpenGLPaintEngine;
+ friend class QGLPaintDevice;
+ friend class QGLWidgetGLPaintDevice;
};
diff --git a/src/opengl/qgl_cl_p.h b/src/opengl/qgl_cl_p.h
index fb573c05b..c3bc68ccb 100644
--- a/src/opengl/qgl_cl_p.h
+++ b/src/opengl/qgl_cl_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp
index 1cb80679c..fbf034988 100644
--- a/src/opengl/qgl_egl.cpp
+++ b/src/opengl/qgl_egl.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,26 +21,26 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtOpenGL/qgl.h>
+#include "qgl_p.h"
#include "qgl_egl_p.h"
QT_BEGIN_NAMESPACE
@@ -74,7 +75,7 @@ void qt_egl_set_format(QEglProperties& props, int deviceType, const QGLFormat& f
props.setValue(EGL_STENCIL_SIZE, f.stencilBufferSize() == -1 ? 1 : f.stencilBufferSize());
if (f.sampleBuffers()) {
props.setValue(EGL_SAMPLE_BUFFERS, 1);
- props.setValue(EGL_SAMPLES, f.samples());
+ props.setValue(EGL_SAMPLES, f.samples() == -1 ? 1 : f.samples());
} else {
props.setValue(EGL_SAMPLE_BUFFERS, 0);
}
@@ -128,4 +129,105 @@ void qt_egl_update_format(const QEglContext& context, QGLFormat& format)
context.clearError();
}
+bool QGLFormat::hasOpenGL()
+{
+ return true;
+}
+
+void QGLContext::reset()
+{
+ Q_D(QGLContext);
+ if (!d->valid)
+ return;
+ d->cleanup();
+ doneCurrent();
+ if (d->eglContext) {
+ if (d->eglSurface != EGL_NO_SURFACE) {
+#ifdef Q_WS_X11
+ // Make sure we don't call eglDestroySurface on a surface which
+ // was created for a different winId:
+ if (d->paintDevice->devType() == QInternal::Widget) {
+ QGLWidget* w = static_cast<QGLWidget*>(d->paintDevice);
+
+ if (w->d_func()->eglSurfaceWindowId == w->winId())
+ eglDestroySurface(d->eglContext->display(), d->eglSurface);
+ } else
+#endif
+ eglDestroySurface(d->eglContext->display(), d->eglSurface);
+ }
+ delete d->eglContext;
+ }
+ d->eglContext = 0;
+ d->eglSurface = EGL_NO_SURFACE;
+ d->crWin = false;
+ d->sharing = false;
+ d->valid = false;
+ d->transpColor = QColor();
+ d->initDone = false;
+ qgl_share_reg()->removeShare(this);
+}
+
+void QGLContext::makeCurrent()
+{
+ Q_D(QGLContext);
+ if (!d->valid || !d->eglContext || d->eglSurface == EGL_NO_SURFACE) {
+ qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
+ return;
+ }
+
+ if (d->eglContext->makeCurrent(d->eglSurface))
+ QGLContextPrivate::setCurrentContext(this);
+}
+
+void QGLContext::doneCurrent()
+{
+ Q_D(QGLContext);
+ if (d->eglContext)
+ d->eglContext->doneCurrent();
+
+ QGLContextPrivate::setCurrentContext(0);
+}
+
+
+void QGLContext::swapBuffers() const
+{
+ Q_D(const QGLContext);
+ if (!d->valid || !d->eglContext)
+ return;
+
+ d->eglContext->swapBuffers(d->eglSurface);
+}
+
+void QGLWidget::setMouseTracking(bool enable)
+{
+ QWidget::setMouseTracking(enable);
+}
+
+QColor QGLContext::overlayTransparentColor() const
+{
+ return d_func()->transpColor;
+}
+
+uint QGLContext::colorIndex(const QColor &c) const
+{
+ Q_UNUSED(c);
+ return 0;
+}
+
+void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
+{
+ Q_UNUSED(fnt);
+ Q_UNUSED(listBase);
+}
+
+void *QGLContext::getProcAddress(const QString &proc) const
+{
+ return (void*)eglGetProcAddress(reinterpret_cast<const char *>(proc.toLatin1().data()));
+}
+
+bool QGLWidgetPrivate::renderCxPm(QPixmap*)
+{
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_egl_p.h b/src/opengl/qgl_egl_p.h
index bdd1e2a31..47a4a1961 100644
--- a/src/opengl/qgl_egl_p.h
+++ b/src/opengl/qgl_egl_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/qgl_mac.mm b/src/opengl/qgl_mac.mm
index 60b94378a..4dd822d30 100644
--- a/src/opengl/qgl_mac.mm
+++ b/src/opengl/qgl_mac.mm
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -460,6 +460,7 @@ void QGLContext::reset()
if (d->cx)
aglDestroyContext((AGLContext)d->cx);
#else
+ QMacCocoaAutoReleasePool pool;
[static_cast<NSOpenGLContext *>(d->cx) release];
#endif
d->cx = 0;
@@ -493,11 +494,7 @@ void QGLContext::makeCurrent()
#else
[static_cast<NSOpenGLContext *>(d->cx) makeCurrentContext];
#endif
- currentCtx = this;
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
+ QGLContextPrivate::setCurrentContext(this);
}
#ifndef QT_MAC_USE_COCOA
@@ -656,9 +653,7 @@ void QGLContext::doneCurrent()
)
return;
- currentCtx = 0;
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
+ QGLContextPrivate::setCurrentContext(0);
#ifndef QT_MAC_USE_COCOA
aglSetCurrentContext(0);
#else
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index 92aea6c41..ab72c9c96 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -59,8 +59,10 @@
#include "QtCore/qthread.h"
#include "QtCore/qthreadstorage.h"
#include "QtCore/qhash.h"
+#include "QtCore/qatomic.h"
#include "private/qwidget_p.h"
#include "qcache.h"
+#include "qglpaintdevice_p.h"
#ifndef QT_OPENGL_ES_1_CL
#define q_vertexType float
@@ -127,7 +129,9 @@ QT_END_INCLUDE_NAMESPACE
class QGLFormatPrivate
{
public:
- QGLFormatPrivate() {
+ QGLFormatPrivate()
+ : ref(1)
+ {
opts = QGL::DoubleBuffer | QGL::DepthBuffer | QGL::Rgba | QGL::DirectRendering | QGL::StencilBuffer;
#if defined(QT_OPENGL_ES_2)
opts |= QGL::SampleBuffers;
@@ -137,6 +141,22 @@ public:
numSamples = -1;
swapInterval = -1;
}
+ QGLFormatPrivate(const QGLFormatPrivate *other)
+ : ref(1),
+ opts(other->opts),
+ pln(other->pln),
+ depthSize(other->depthSize),
+ accumSize(other->accumSize),
+ stencilSize(other->stencilSize),
+ redSize(other->redSize),
+ greenSize(other->greenSize),
+ blueSize(other->blueSize),
+ alphaSize(other->alphaSize),
+ numSamples(other->numSamples),
+ swapInterval(other->swapInterval)
+ {
+ }
+ QAtomicInt ref;
QGL::FormatOptions opts;
int pln;
int depthSize;
@@ -155,6 +175,7 @@ class QGLWidgetPrivate : public QWidgetPrivate
Q_DECLARE_PUBLIC(QGLWidget)
public:
QGLWidgetPrivate() : QWidgetPrivate()
+ , disable_clear_on_painter_begin(false)
#ifdef Q_WS_QWS
, wsurf(0)
#endif
@@ -171,10 +192,15 @@ public:
void cleanupColormaps();
QGLContext *glcx;
+ QGLWidgetGLPaintDevice glDevice;
bool autoSwap;
QGLColormap cmap;
+#ifndef QT_OPENGL_ES
QMap<QString, int> displayListCache;
+#endif
+
+ bool disable_clear_on_painter_begin;
#if defined(Q_WS_WIN)
void updateColormap();
@@ -193,11 +219,40 @@ public:
#endif
};
-struct QGLContextGroupResources
+class QGLContextResource;
+class QGLSharedResourceGuard;
+
+// QGLContextPrivate has the responsibility of creating context groups.
+// QGLContextPrivate and QGLShareRegister will both maintain the reference counter and destroy
+// context groups when needed.
+// QGLShareRegister has the responsibility of keeping the context pointer up to date.
+class QGLContextGroup
{
- QGLContextGroupResources() : refs(1) { }
- QGLExtensionFuncs extensionFuncs;
- QAtomicInt refs;
+public:
+ ~QGLContextGroup();
+
+ QGLExtensionFuncs &extensionFuncs() {return m_extensionFuncs;}
+ const QGLContext *context() const {return m_context;}
+ bool isSharing() const { return m_shares.size() >= 2; }
+
+ void addGuard(QGLSharedResourceGuard *guard);
+ void removeGuard(QGLSharedResourceGuard *guard);
+private:
+ QGLContextGroup(const QGLContext *context) : m_context(context), m_guards(0), m_refs(1) { }
+
+ QGLExtensionFuncs m_extensionFuncs;
+ const QGLContext *m_context; // context group's representative
+ QList<const QGLContext *> m_shares;
+ QHash<QGLContextResource *, void *> m_resources;
+ QGLSharedResourceGuard *m_guards; // double-linked list of active guards.
+ QAtomicInt m_refs;
+
+ void cleanupResources(const QGLContext *ctx);
+
+ friend class QGLShareRegister;
+ friend class QGLContext;
+ friend class QGLContextPrivate;
+ friend class QGLContextResource;
};
class QGLTexture;
@@ -206,12 +261,14 @@ class QGLContextPrivate
{
Q_DECLARE_PUBLIC(QGLContext)
public:
- explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {groupResources = new QGLContextGroupResources;}
- ~QGLContextPrivate() {if (!groupResources->refs.deref()) delete groupResources;}
- QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, bool clean);
+ explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {group = new QGLContextGroup(context);}
+ ~QGLContextPrivate();
+ QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format,
+ QGLContext::BindOptions options);
QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key,
- bool clean = false);
- QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean, bool canInvert = false);
+ QGLContext::BindOptions options);
+ QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format,
+ QGLContext::BindOptions options);
QGLTexture *textureCacheLookup(const qint64 key, GLenum target);
void init(QPaintDevice *dev, const QGLFormat &format);
QImage convertToGLFormat(const QImage &image, bool force_premul, GLenum texture_format);
@@ -230,6 +287,7 @@ public:
#endif
#if defined(QT_OPENGL_ES)
QEglContext *eglContext;
+ EGLSurface eglSurface;
#elif defined(Q_WS_X11) || defined(Q_WS_MAC)
void* cx;
#endif
@@ -241,7 +299,8 @@ public:
quint32 gpm;
int screen;
QHash<QPixmapData*, QPixmap> boundPixmaps;
- QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key, bool canInvert);
+ QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key,
+ QGLContext::BindOptions options);
static void destroyGlSurfaceForPixmap(QPixmapData*);
static void unbindPixmapFromTexture(QPixmapData*);
#endif
@@ -252,14 +311,12 @@ public:
#endif
QGLFormat glFormat;
QGLFormat reqFormat;
- GLuint pbo;
GLuint fbo;
uint valid : 1;
uint sharing : 1;
uint initDone : 1;
uint crWin : 1;
- uint clear_on_painter_begin : 1;
uint internal_context : 1;
uint version_flags_cached : 1;
QPaintDevice *paintDevice;
@@ -267,22 +324,25 @@ public:
QGLContext *q_ptr;
QGLFormat::OpenGLVersionFlags version_flags;
- QGLContextGroupResources *groupResources;
+ QGLContextGroup *group;
GLint max_texture_size;
GLuint current_fbo;
+ GLuint default_fbo;
QPaintEngine *active_engine;
+ static inline QGLContextGroup *contextGroup(const QGLContext *ctx) { return ctx->d_ptr->group; }
+
#ifdef Q_WS_WIN
- static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->groupResources->extensionFuncs; }
+ static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *ctx) { return ctx->d_ptr->group->extensionFuncs(); }
#endif
#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
static QGLExtensionFuncs qt_extensionFuncs;
- static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *) { return qt_extensionFuncs; }
+ static inline QGLExtensionFuncs& extensionFuncs(const QGLContext *) { return qt_extensionFuncs; }
#endif
- QPixmapFilter *createPixmapFilter(int type) const;
+ static void setCurrentContext(QGLContext *context);
};
// ### make QGLContext a QObject in 5.0 and remove the proxy stuff
@@ -299,55 +359,6 @@ Q_SIGNALS:
void aboutToDestroyContext(const QGLContext *context);
};
-class QGLPixelBuffer;
-class QGLFramebufferObject;
-class QWSGLWindowSurface;
-class QGLWindowSurface;
-class QGLPixmapData;
-class QGLDrawable {
-public:
- QGLDrawable() : widget(0), buffer(0), fbo(0)
-#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
- , wsurf(0)
-#endif
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- , pixmapData(0)
-#endif
- {}
- void setDevice(QPaintDevice *pdev);
- void swapBuffers();
- void makeCurrent();
- void doneCurrent();
- QSize size() const;
- QGLFormat format() const;
- GLuint bindTexture(const QImage &image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA);
- GLuint bindTexture(const QPixmap &pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA);
- QColor backgroundColor() const;
- QGLContext *context() const;
- bool autoFillBackground() const;
- bool hasTransparentBackground() const;
-
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- QGLPixmapData *copyOnBegin() const;
-#endif
-
-private:
- bool wasBound;
- QGLWidget *widget;
- QGLPixelBuffer *buffer;
- QGLFramebufferObject *fbo;
-#ifdef Q_WS_QWS
- QWSGLWindowSurface *wsurf;
-#elif !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- QGLWindowSurface *wsurf;
-#endif
-
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- QGLPixmapData *pixmapData;
-#endif
- int previous_fbo;
-};
-
// GL extension definitions
class QGLExtensions {
public:
@@ -365,7 +376,8 @@ public:
NVFloatBuffer = 0x00000400,
PixelBufferObject = 0x00000800,
FramebufferBlit = 0x00001000,
- NPOTTextures = 0x00002000
+ NPOTTextures = 0x00002000,
+ BGRATextureFormat = 0x00004000
};
Q_DECLARE_FLAGS(Extensions, Extension)
@@ -378,48 +390,76 @@ public:
Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions)
-struct QGLThreadContext {
- QGLContext *context;
-};
-extern QThreadStorage<QGLThreadContext *> qgl_context_storage;
-
-class QGLShareRegister
+class Q_AUTOTEST_EXPORT QGLShareRegister
{
public:
QGLShareRegister() {}
- ~QGLShareRegister() { reg.clear(); }
+ ~QGLShareRegister() {}
- bool checkSharing(const QGLContext *context1, const QGLContext *context2);
void addShare(const QGLContext *context, const QGLContext *share);
QList<const QGLContext *> shares(const QGLContext *context);
void removeShare(const QGLContext *context);
-private:
- // Use a context's 'groupResources' pointer to uniquely identify a group.
- typedef QList<const QGLContext *> ContextList;
- typedef QHash<const QGLContextGroupResources *, ContextList> SharingHash;
- SharingHash reg;
};
extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg();
+// Temporarily make a context current if not already current or
+// shared with the current contex. The previous context is made
+// current when the object goes out of scope.
+class Q_OPENGL_EXPORT QGLShareContextScope
+{
+public:
+ QGLShareContextScope(const QGLContext *ctx)
+ : m_oldContext(0)
+ {
+ QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (currentContext != ctx && !QGLContext::areSharing(ctx, currentContext)) {
+ m_oldContext = currentContext;
+ m_ctx = const_cast<QGLContext *>(ctx);
+ m_ctx->makeCurrent();
+ } else {
+ m_ctx = currentContext;
+ }
+ }
+
+ operator QGLContext *()
+ {
+ return m_ctx;
+ }
+
+ QGLContext *operator->()
+ {
+ return m_ctx;
+ }
+
+ ~QGLShareContextScope()
+ {
+ if (m_oldContext)
+ m_oldContext->makeCurrent();
+ }
+
+private:
+ QGLContext *m_oldContext;
+ QGLContext *m_ctx;
+};
+
class QGLTexture {
public:
QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D,
- bool _clean = false, bool _yInverted = false)
- : context(ctx), id(tx_id), target(tx_target), clean(_clean), yInverted(_yInverted)
+ QGLContext::BindOptions opt = QGLContext::DefaultBindOption)
+ : context(ctx),
+ id(tx_id),
+ target(tx_target),
+ options(opt)
#if defined(Q_WS_X11)
- , boundPixmap(0)
+ , boundPixmap(0)
#endif
{}
~QGLTexture() {
- if (clean) {
- QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());
- QGLContext *ctx = const_cast<QGLContext *>(context);
- Q_ASSERT(ctx);
- bool switch_context = current != ctx && !qgl_share_reg()->checkSharing(current, ctx);
- if (switch_context)
- ctx->makeCurrent();
+ if (options & QGLContext::MemoryManagedBindOption) {
+ Q_ASSERT(context);
+ QGLShareContextScope scope(context);
#if defined(Q_WS_X11)
// Although glXReleaseTexImage is a glX call, it must be called while there
// is a current context - the context the pixmap was bound to a texture in.
@@ -429,16 +469,15 @@ public:
QGLContextPrivate::unbindPixmapFromTexture(boundPixmap);
#endif
glDeleteTextures(1, &id);
- if (switch_context && current)
- current->makeCurrent();
}
}
QGLContext *context;
GLuint id;
GLenum target;
- bool clean;
- bool yInverted; // NOTE: Y-Inverted textures are for internal use only!
+
+ QGLContext::BindOptions options;
+
#if defined(Q_WS_X11)
QPixmapData* boundPixmap;
#endif
@@ -462,28 +501,20 @@ public:
static QGLTextureCache *instance();
static void deleteIfEmpty();
static void imageCleanupHook(qint64 cacheKey);
- static void pixmapCleanupHook(QPixmap* pixmap);
+ static void cleanupTextures(QPixmap* pixmap);
+#ifdef Q_WS_X11
+ // X11 needs to catch pixmap data destruction to delete EGL/GLX pixmap surfaces
+ static void cleanupPixmapSurfaces(QPixmap* pixmap);
+#endif
private:
QCache<qint64, QGLTexture> m_cache;
};
-#ifdef Q_WS_QWS
-extern QPaintEngine* qt_qgl_paint_engine();
-
-extern EGLDisplay qt_qgl_egl_display();
-#endif
+extern Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine();
-inline bool qt_gl_preferGL2Engine()
-{
-#if defined(QT_OPENGL_ES_2)
- return true;
-#else
- return (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0)
- && qgetenv("QT_GL_USE_OPENGL1ENGINE").isEmpty();
-#endif
-}
+bool qt_gl_preferGL2Engine();
inline GLenum qt_gl_preferredTextureFormat()
{
@@ -503,26 +534,67 @@ inline GLenum qt_gl_preferredTextureTarget()
}
// One resource per group of shared contexts.
-class QGLContextResource : public QObject
+class Q_AUTOTEST_EXPORT QGLContextResource
{
- Q_OBJECT
public:
typedef void (*FreeFunc)(void *);
- QGLContextResource(FreeFunc f, QObject *parent = 0);
+ QGLContextResource(FreeFunc f);
~QGLContextResource();
// Set resource 'value' for 'key' and all its shared contexts.
void insert(const QGLContext *key, void *value);
// Return resource for 'key' or a shared context.
void *value(const QGLContext *key);
- // Free resource for 'key' and all its shared contexts.
- void remove(const QGLContext *key);
-private slots:
- // Remove entry 'key' from cache and delete resource if there are no shared contexts.
- void aboutToDestroyContext(const QGLContext *key);
+ // Cleanup 'value' in response to a context group being destroyed.
+ void cleanup(const QGLContext *ctx, void *value);
private:
- typedef QHash<const QGLContext *, void *> ResourceHash;
- ResourceHash m_resources;
FreeFunc free;
+ QAtomicInt active;
+};
+
+// 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 QGLSharedResourceGuard
+{
+public:
+ QGLSharedResourceGuard(const QGLContext *context)
+ : m_group(0), m_id(0), m_next(0), m_prev(0)
+ {
+ setContext(context);
+ }
+ QGLSharedResourceGuard(const QGLContext *context, GLuint id)
+ : m_group(0), m_id(id), m_next(0), m_prev(0)
+ {
+ setContext(context);
+ }
+ ~QGLSharedResourceGuard();
+
+ const QGLContext *context() const
+ {
+ return m_group ? m_group->context() : 0;
+ }
+
+ void setContext(const QGLContext *context);
+
+ GLuint id() const
+ {
+ return m_id;
+ }
+
+ void setId(GLuint id)
+ {
+ m_id = id;
+ }
+
+private:
+ QGLContextGroup *m_group;
+ GLuint m_id;
+ QGLSharedResourceGuard *m_next;
+ QGLSharedResourceGuard *m_prev;
+
+ friend class QGLContextGroup;
};
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_qws.cpp b/src/opengl/qgl_qws.cpp
index bc36b2137..a189c20fe 100644
--- a/src/opengl/qgl_qws.cpp
+++ b/src/opengl/qgl_qws.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,27 +21,27 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qgl.h"
#include "qgl_egl_p.h"
+#include "qglpixelbuffer.h"
#include <qglscreen_qws.h>
#include <qscreenproxy_qws.h>
@@ -72,7 +73,8 @@ static QGLScreen *glScreenForDevice(QPaintDevice *device)
screenNumber = 0;
screen = screen->subScreens()[screenNumber];
}
- while (screen->classId() == QScreen::ProxyClass) {
+ while (screen->classId() == QScreen::ProxyClass ||
+ screen->classId() == QScreen::TransformedClass) {
screen = static_cast<QProxyScreen *>(screen)->screen();
}
if (screen->classId() == QScreen::GLClass)
@@ -86,12 +88,6 @@ static QGLScreen *glScreenForDevice(QPaintDevice *device)
*****************************************************************************/
//#define DEBUG_OPENGL_REGION_UPDATE
-bool QGLFormat::hasOpenGL()
-{
- return true;
-}
-
-
bool QGLFormat::hasOpenGLOverlays()
{
QGLScreen *glScreen = glScreenForDevice(0);
@@ -116,17 +112,17 @@ void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
props.setPixelFormat(glScreen->pixelFormat());
}
-static bool qt_egl_create_surface
+static EGLSurface qt_egl_create_surface
(QEglContext *context, QPaintDevice *device,
const QEglProperties *properties = 0)
{
// Get the screen surface functions, which are used to create native ids.
QGLScreen *glScreen = glScreenForDevice(device);
if (!glScreen)
- return false;
+ return EGL_NO_SURFACE;
QGLScreenSurfaceFunctions *funcs = glScreen->surfaceFunctions();
if (!funcs)
- return false;
+ return EGL_NO_SURFACE;
// Create the native drawable for the paint device.
int devType = device->devType();
@@ -142,7 +138,7 @@ static bool qt_egl_create_surface
}
if (!ok) {
qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable");
- return false;
+ return EGL_NO_SURFACE;
}
// Create the EGL surface to draw into, based on the native drawable.
@@ -159,12 +155,9 @@ static bool qt_egl_create_surface
surf = eglCreatePixmapSurface
(context->display(), context->config(), pixmapDrawable, props);
}
- if (surf == EGL_NO_SURFACE) {
+ if (surf == EGL_NO_SURFACE)
qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError());
- return false;
- }
- context->setSurface(surf);
- return true;
+ return surf;
}
bool QGLContext::chooseContext(const QGLContext* shareContext)
@@ -213,6 +206,9 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
d->eglContext = 0;
return false;
}
+ d->sharing = d->eglContext->isSharing();
+ if (d->sharing && shareContext)
+ const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
#if defined(EGL_VERSION_1_1)
if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
@@ -222,7 +218,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
// Create the EGL surface to draw into. We cannot use
// QEglContext::createSurface() because it does not have
// access to the QGLScreen.
- if (!qt_egl_create_surface(d->eglContext, device())) {
+ d->eglSurface = qt_egl_create_surface(d->eglContext, device());
+ if (d->eglSurface == EGL_NO_SURFACE) {
delete d->eglContext;
d->eglContext = 0;
return false;
@@ -232,96 +229,11 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
}
-void QGLContext::reset()
-{
- Q_D(QGLContext);
- if (!d->valid)
- return;
- d->cleanup();
- doneCurrent();
- if (d->eglContext) {
- delete d->eglContext;
- d->eglContext = 0;
- }
- d->crWin = false;
- d->sharing = false;
- d->valid = false;
- d->transpColor = QColor();
- d->initDone = false;
- qgl_share_reg()->removeShare(this);
-}
-
-void QGLContext::makeCurrent()
-{
- Q_D(QGLContext);
- if(!d->valid || !d->eglContext) {
- qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
- return;
- }
-
- if (d->eglContext->makeCurrent()) {
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
- currentCtx = this;
- }
-}
-
-void QGLContext::doneCurrent()
-{
- Q_D(QGLContext);
- if (d->eglContext)
- d->eglContext->doneCurrent();
-
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
- currentCtx = 0;
-}
-
-
-void QGLContext::swapBuffers() const
-{
- Q_D(const QGLContext);
- if(!d->valid || !d->eglContext)
- return;
-
- d->eglContext->swapBuffers();
-}
-
-QColor QGLContext::overlayTransparentColor() const
-{
- return QColor(0, 0, 0); // Invalid color
-}
-
-uint QGLContext::colorIndex(const QColor &c) const
-{
- //### color index doesn't work on egl
- Q_UNUSED(c);
- return 0;
-}
-
-void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
-{
- Q_UNUSED(fnt);
- Q_UNUSED(listBase);
-}
-
-void *QGLContext::getProcAddress(const QString &proc) const
-{
- return (void*)eglGetProcAddress(reinterpret_cast<const char *>(proc.toLatin1().data()));
-}
-
bool QGLWidget::event(QEvent *e)
{
return QWidget::event(e);
}
-void QGLWidget::setMouseTracking(bool enable)
-{
- QWidget::setMouseTracking(enable);
-}
-
void QGLWidget::resizeEvent(QResizeEvent *)
{
@@ -386,11 +298,6 @@ void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
}
}
-bool QGLWidgetPrivate::renderCxPm(QPixmap*)
-{
- return false;
-}
-
void QGLWidgetPrivate::cleanupColormaps()
{
}
@@ -411,7 +318,29 @@ void QGLExtensions::init()
if (init_done)
return;
init_done = true;
+
+ // We need a context current to initialize the extensions,
+ // but getting a valid EGLNativeWindowType this early can be
+ // problematic under QWS. So use a pbuffer instead.
+ //
+ // Unfortunately OpenGL/ES 2.0 systems don't normally
+ // support pbuffers, so we have no choice but to try
+ // our luck with a window on those systems.
+#if defined(QT_OPENGL_ES_2)
+ QGLWidget tmpWidget;
+ tmpWidget.makeCurrent();
+
init_extensions();
+
+ tmpWidget.doneCurrent();
+#else
+ QGLPixelBuffer pbuffer(16, 16);
+ pbuffer.makeCurrent();
+
+ init_extensions();
+
+ pbuffer.doneCurrent();
+#endif
}
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp
index 09e7b10f9..5b5820ac4 100644
--- a/src/opengl/qgl_win.cpp
+++ b/src/opengl/qgl_win.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -660,6 +660,8 @@ public:
int dmy_pf = ChoosePixelFormat(dmy_pdc, &dmy_pfd);
SetPixelFormat(dmy_pdc, dmy_pf, &dmy_pfd);
dmy_rc = wglCreateContext(dmy_pdc);
+ old_dc = wglGetCurrentDC();
+ old_context = wglGetCurrentContext();
wglMakeCurrent(dmy_pdc, dmy_rc);
}
@@ -668,10 +670,14 @@ public:
wglDeleteContext(dmy_rc);
ReleaseDC(dmy_id, dmy_pdc);
DestroyWindow(dmy_id);
+ if (old_dc && old_context)
+ wglMakeCurrent(old_dc, old_context);
}
HDC dmy_pdc;
HGLRC dmy_rc;
+ HDC old_dc;
+ HGLRC old_context;
WId dmy_id;
};
@@ -1173,11 +1179,7 @@ void QGLContext::makeCurrent()
}
if (wglMakeCurrent(d->dc, d->rc)) {
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
- currentCtx = this;
+ QGLContextPrivate::setCurrentContext(this);
} else {
qwglError("QGLContext::makeCurrent()", "wglMakeCurrent");
}
@@ -1187,10 +1189,8 @@ void QGLContext::makeCurrent()
void QGLContext::doneCurrent()
{
Q_D(QGLContext);
- currentCtx = 0;
wglMakeCurrent(0, 0);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
+ QGLContextPrivate::setCurrentContext(0);
if (deviceIsPixmap() && d->hbitmap) {
QPixmap *pm = static_cast<QPixmap *>(d->paintDevice);
*pm = QPixmap::fromWinHBITMAP(d->hbitmap);
diff --git a/src/opengl/qgl_wince.cpp b/src/opengl/qgl_wince.cpp
index 862c7f699..255311010 100644
--- a/src/opengl/qgl_wince.cpp
+++ b/src/opengl/qgl_wince.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -54,9 +54,9 @@
#include <windows.h>
-#include "qegl_p.h"
-#include "qgl_egl_p.h"
-#include "qgl_cl_p.h"
+#include <private/qegl_p.h>
+#include <private/qgl_egl_p.h>
+#include <private/qgl_cl_p.h>
QT_BEGIN_NAMESPACE
@@ -112,11 +112,6 @@ void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device)
}
-bool QGLFormat::hasOpenGL()
-{
- return true;
-}
-
static bool opengl32dll = false;
bool QGLFormat::hasOpenGLOverlays()
@@ -171,6 +166,9 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
d->eglContext = 0;
return false;
}
+ d->sharing = d->eglContext->isSharing();
+ if (d->sharing && shareContext)
+ const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
#if defined(EGL_VERSION_1_1)
if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
@@ -178,7 +176,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
#endif
// Create the EGL surface to draw into.
- if (!d->eglContext->createSurface(device())) {
+ d->eglSurface = d->eglContext->createSurface(device());
+ if (d->eglSurface == EGL_NO_SURFACE) {
delete d->eglContext;
d->eglContext = 0;
return false;
@@ -415,90 +414,6 @@ const QRgb* QGLCmap::colors() const
}
-void QGLContext::reset()
-{
- Q_D(QGLContext);
- if (!d->valid)
- return;
- d->cleanup();
- doneCurrent();
- if (d->eglContext) {
- delete d->eglContext;
- d->eglContext = 0;
- }
- d->crWin = false;
- d->sharing = false;
- d->valid = false;
- d->transpColor = QColor();
- d->initDone = false;
- qgl_share_reg()->removeShare(this);
-}
-
-
-//
-// NOTE: In a multi-threaded environment, each thread has a current
-// context. If we want to make this code thread-safe, we probably
-// have to use TLS (thread local storage) for keeping current contexts.
-//
-
-void QGLContext::makeCurrent()
-{
-
- Q_D(QGLContext);
- if(!d->valid || !d->eglContext) {
- qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
- return;
- }
-
- if (d->eglContext->makeCurrent()) {
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
- currentCtx = this;
- }
-}
-
-
-void QGLContext::doneCurrent()
-{
-
- Q_D(QGLContext);
- if (d->eglContext)
- d->eglContext->doneCurrent();
-
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
- currentCtx = 0;
-}
-
-void QGLContext::swapBuffers() const
-{
- Q_D(const QGLContext);
- if(!d->valid || !d->eglContext)
- return;
-
- d->eglContext->swapBuffers();
-}
-
-
-QColor QGLContext::overlayTransparentColor() const
-{
- return d_func()->transpColor;
-}
-
-
-void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
-{
- Q_UNUSED(fnt);
- Q_UNUSED(listBase);
-}
-
-void *QGLContext::getProcAddress(const QString &proc) const
-{
- return (void*)eglGetProcAddress(reinterpret_cast<const char *>(proc.toLatin1().data()));
-}
-
/*****************************************************************************
QGLWidget Win32/WGL-specific code
*****************************************************************************/
@@ -577,12 +492,6 @@ bool QGLWidget::event(QEvent *e)
}
-void QGLWidget::setMouseTracking(bool enable)
-{
- QWidget::setMouseTracking(enable);
-}
-
-
void QGLWidget::resizeEvent(QResizeEvent *)
{
Q_D(QGLWidget);
@@ -682,11 +591,6 @@ void QGLWidget::setContext(QGLContext *context,
}
-bool QGLWidgetPrivate::renderCxPm(QPixmap*)
-{
- return false;
-}
-
void QGLWidgetPrivate::cleanupColormaps()
{
Q_Q(QGLWidget);
@@ -730,7 +634,14 @@ void QGLExtensions::init()
if (init_done)
return;
init_done = true;
+
+ // We need a context current to initialize the extensions.
+ QGLWidget tmpWidget;
+ tmpWidget.makeCurrent();
+
init_extensions();
+
+ tmpWidget.doneCurrent();
}
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp
index dccdf6323..a037282f4 100644
--- a/src/opengl/qgl_x11.cpp
+++ b/src/opengl/qgl_x11.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -53,6 +53,7 @@
#include <private/qfontengine_ft_p.h>
#include <private/qt_x11_p.h>
#include <private/qpixmap_x11_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
#ifdef Q_OS_HPUX
// for GLXPBuffer
#include <private/qglpixelbuffer_p.h>
@@ -331,6 +332,62 @@ static void find_trans_colors()
QGLFormat UNIX/GLX-specific code
*****************************************************************************/
+void* qglx_getProcAddress(const char* procName)
+{
+ // On systems where the GL driver is pluggable (like Mesa), we have to use
+ // the glXGetProcAddressARB extension to resolve other function pointers as
+ // the symbols wont be in the GL library, but rather in a plugin loaded by
+ // the GL library.
+ typedef void* (*qt_glXGetProcAddressARB)(const char *);
+ static qt_glXGetProcAddressARB glXGetProcAddressARB = 0;
+ static bool triedResolvingGlxGetProcAddress = false;
+ if (!triedResolvingGlxGetProcAddress) {
+ triedResolvingGlxGetProcAddress = true;
+ QList<QByteArray> glxExt = QByteArray(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)).split(' ');
+ if (glxExt.contains("GLX_ARB_get_proc_address")) {
+#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
+ void *handle = dlopen(NULL, RTLD_LAZY);
+ if (handle) {
+ glXGetProcAddressARB = (qt_glXGetProcAddressARB) dlsym(handle, "glXGetProcAddressARB");
+ dlclose(handle);
+ }
+ if (!glXGetProcAddressARB)
+#endif
+ {
+#if !defined(QT_NO_LIBRARY)
+ extern const QString qt_gl_library_name();
+ QLibrary lib(qt_gl_library_name());
+ glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB");
+#endif
+ }
+ }
+ }
+
+ void *procAddress = 0;
+ if (glXGetProcAddressARB)
+ procAddress = glXGetProcAddressARB(procName);
+
+ // If glXGetProcAddress didn't work, try looking the symbol up in the GL library
+#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
+ if (!procAddress) {
+ void *handle = dlopen(NULL, RTLD_LAZY);
+ if (handle) {
+ procAddress = dlsym(handle, procName);
+ dlclose(handle);
+ }
+ }
+#endif
+#if !defined(QT_NO_LIBRARY)
+ if (!procAddress) {
+ extern const QString qt_gl_library_name();
+ QLibrary lib(qt_gl_library_name());
+ procAddress = lib.resolve(procName);
+ }
+#endif
+
+ return procAddress;
+}
+
bool QGLFormat::hasOpenGL()
{
return glXQueryExtension(X11->display, 0, 0) != 0;
@@ -466,8 +523,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
if (!d->gpm)
return false;
}
- QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
- if (glxExt.contains(QLatin1String("GLX_SGI_video_sync"))) {
+ QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(xinfo->display(), xinfo->screen())).split(' ');
+ if (glxExt.contains("GLX_SGI_video_sync")) {
if (d->glFormat.swapInterval() == -1)
d->glFormat.setSwapInterval(0);
} else {
@@ -791,22 +848,15 @@ void QGLContext::makeCurrent()
if (!ok)
qWarning("QGLContext::makeCurrent(): Failed.");
- if (ok) {
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
- currentCtx = this;
- }
+ if (ok)
+ QGLContextPrivate::setCurrentContext(this);
}
void QGLContext::doneCurrent()
{
Q_D(QGLContext);
glXMakeCurrent(qt_x11Info(d->paintDevice)->display(), 0, 0);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
- currentCtx = 0;
+ QGLContextPrivate::setCurrentContext(0);
}
@@ -824,25 +874,11 @@ void QGLContext::swapBuffers() const
static qt_glXWaitVideoSyncSGI glXWaitVideoSyncSGI = 0;
static bool resolved = false;
if (!resolved) {
- QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
- if (glxExt.contains(QLatin1String("GLX_SGI_video_sync"))) {
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
- void *handle = dlopen(NULL, RTLD_LAZY);
- if (handle) {
- glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI) dlsym(handle, "glXGetVideoSyncSGI");
- glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI) dlsym(handle, "glXWaitVideoSyncSGI");
- dlclose(handle);
- }
- if (!glXGetVideoSyncSGI)
-#endif
- {
-#if !defined(QT_NO_LIBRARY)
- extern const QString qt_gl_library_name();
- QLibrary lib(qt_gl_library_name());
- glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI) lib.resolve("glXGetVideoSyncSGI");
- glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI) lib.resolve("glXWaitVideoSyncSGI");
-#endif
- }
+ const QX11Info *xinfo = qt_x11Info(d->paintDevice);
+ QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(xinfo->display(), xinfo->screen())).split(' ');
+ if (glxExt.contains("GLX_SGI_video_sync")) {
+ glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI)qglx_getProcAddress("glXGetVideoSyncSGI");
+ glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI)qglx_getProcAddress("glXWaitVideoSyncSGI");
}
resolved = true;
}
@@ -1071,8 +1107,8 @@ void *QGLContext::getProcAddress(const QString &proc) const
if (resolved && !glXGetProcAddressARB)
return 0;
if (!glXGetProcAddressARB) {
- QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
- if (glxExt.contains(QLatin1String("GLX_ARB_get_proc_address"))) {
+ QList<QByteArray> glxExt = QByteArray(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)).split(' ');
+ if (glxExt.contains("GLX_ARB_get_proc_address")) {
#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
void *handle = dlopen(NULL, RTLD_LAZY);
if (handle) {
@@ -1308,7 +1344,6 @@ void QGLWidget::setContext(QGLContext *context,
QGLContext* oldcx = d->glcx;
d->glcx = context;
-
if (parentWidget()) {
// force creation of delay-created widgets
parentWidget()->winId();
@@ -1560,7 +1595,7 @@ typedef void (*qt_glXReleaseTexImageEXT)(Display*, GLXDrawable, int);
static qt_glXBindTexImageEXT glXBindTexImageEXT = 0;
static qt_glXReleaseTexImageEXT glXReleaseTexImageEXT = 0;
-bool qt_resolveTextureFromPixmap()
+static bool qt_resolveTextureFromPixmap(QPaintDevice *paintDevice)
{
static bool resolvedTextureFromPixmap = false;
@@ -1573,24 +1608,11 @@ bool qt_resolveTextureFromPixmap()
{
return false; // Can't use TFP without NPOT
}
-
- QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
- if (glxExt.contains(QLatin1String("GLX_EXT_texture_from_pixmap"))) {
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
- void *handle = dlopen(NULL, RTLD_LAZY);
- if (handle) {
- glXBindTexImageEXT = (qt_glXBindTexImageEXT) dlsym(handle, "glXBindTexImageEXT");
- glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) dlsym(handle, "glXReleaseTexImageEXT");
- dlclose(handle);
- }
- if (!glXBindTexImageEXT)
-#endif
- {
- extern const QString qt_gl_library_name();
- QLibrary lib(qt_gl_library_name());
- glXBindTexImageEXT = (qt_glXBindTexImageEXT) lib.resolve("glXBindTexImageEXT");
- glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) lib.resolve("glXReleaseTexImageEXT");
- }
+ const QX11Info *xinfo = qt_x11Info(paintDevice);
+ QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(xinfo->display(), xinfo->screen())).split(' ');
+ if (glxExt.contains("GLX_EXT_texture_from_pixmap")) {
+ glXBindTexImageEXT = (qt_glXBindTexImageEXT) qglx_getProcAddress("glXBindTexImageEXT");
+ glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) qglx_getProcAddress("glXReleaseTexImageEXT");
}
}
@@ -1599,7 +1621,8 @@ bool qt_resolveTextureFromPixmap()
#endif //defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
-QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, const qint64 key, bool canInvert)
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, const qint64 key,
+ QGLContext::BindOptions options)
{
#if !defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
return 0;
@@ -1608,7 +1631,7 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, con
Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
- if (!qt_resolveTextureFromPixmap())
+ if (!qt_resolveTextureFromPixmap(paintDevice))
return 0;
QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
@@ -1632,7 +1655,7 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, con
GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
// QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can:
- GLX_Y_INVERTED_EXT, canInvert ? GLX_DONT_CARE : False,
+ GLX_Y_INVERTED_EXT, options & QGLContext::CanFlipNativePixmapBindOption ? GLX_DONT_CARE : False,
XNone
};
configList = glXChooseFBConfig(x11Info.display(), x11Info.screen(), configAttribs, &configCount);
@@ -1683,7 +1706,7 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, con
pixmapData->gl_surface = (Qt::HANDLE)glxPixmap;
// Make sure the cleanup hook gets called so we can delete the glx pixmap
- pixmapData->is_cached = true;
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData);
}
GLuint textureId;
@@ -1693,9 +1716,11 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, con
glBindTexture(GL_TEXTURE_2D, textureId);
- QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, false);
- texture->yInverted = (hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted);
- if (texture->yInverted)
+ if (!((hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted)))
+ options &= ~QGLContext::InvertedYBindOption;
+
+ QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
+ if (texture->options & QGLContext::InvertedYBindOption)
pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
// We assume the cost of bound pixmaps is zero
diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp
index 7452c92f7..b51c23998 100644
--- a/src/opengl/qgl_x11egl.cpp
+++ b/src/opengl/qgl_x11egl.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -42,6 +42,7 @@
#include "qgl.h"
#include <private/qt_x11_p.h>
#include <private/qpixmap_x11_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
#include <private/qgl_p.h>
#include <private/qpaintengine_opengl_p.h>
#include "qgl_egl_p.h"
@@ -51,11 +52,6 @@
QT_BEGIN_NAMESPACE
-bool QGLFormat::hasOpenGL()
-{
- return true;
-}
-
bool QGLFormat::hasOpenGLOverlays()
{
return false;
@@ -91,9 +87,19 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
qt_egl_add_platform_config(configProps, device());
configProps.setRenderableType(QEgl::OpenGL);
+ QEgl::PixelFormatMatch matchType = QEgl::BestPixelFormat;
+ if (device()->depth() == 16) {
+ configProps.setValue(EGL_RED_SIZE, 5);
+ configProps.setValue(EGL_GREEN_SIZE, 6);
+ configProps.setValue(EGL_BLUE_SIZE, 5);
+ configProps.setValue(EGL_ALPHA_SIZE, 0);
+ matchType = QEgl::ExactPixelFormat;
+ }
+ configProps.setRenderableType(QEgl::OpenGL);
+
// Search for a matching configuration, reducing the complexity
// each time until we get something that matches.
- if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) {
+ if (!d->eglContext->chooseConfig(configProps, matchType)) {
delete d->eglContext;
d->eglContext = 0;
return false;
@@ -109,6 +115,9 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
d->eglContext = 0;
return false;
}
+ d->sharing = d->eglContext->isSharing();
+ if (d->sharing && shareContext)
+ const_cast<QGLContext *>(shareContext)->d_func()->sharing = true;
#if defined(EGL_VERSION_1_1)
if (d->glFormat.swapInterval() != -1 && devType == QInternal::Widget)
@@ -118,93 +127,6 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
return true;
}
-
-void QGLContext::reset()
-{
- Q_D(QGLContext);
- if (!d->valid)
- return;
- d->cleanup();
- doneCurrent();
- if (d->eglContext) {
- delete d->eglContext;
- d->eglContext = 0;
- }
- d->crWin = false;
- d->sharing = false;
- d->valid = false;
- d->transpColor = QColor();
- d->initDone = false;
- qgl_share_reg()->removeShare(this);
-}
-
-void QGLContext::makeCurrent()
-{
- Q_D(QGLContext);
- if(!d->valid || !d->eglContext) {
- qWarning("QGLContext::makeCurrent(): Cannot make invalid context current");
- return;
- }
-
- if (d->eglContext->makeCurrent()) {
- if (!qgl_context_storage.hasLocalData() && QThread::currentThread())
- qgl_context_storage.setLocalData(new QGLThreadContext);
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = this;
- currentCtx = this;
- }
-}
-
-void QGLContext::doneCurrent()
-{
- Q_D(QGLContext);
- if (d->eglContext)
- d->eglContext->doneCurrent();
-
- if (qgl_context_storage.hasLocalData())
- qgl_context_storage.localData()->context = 0;
- currentCtx = 0;
-}
-
-
-void QGLContext::swapBuffers() const
-{
- Q_D(const QGLContext);
- if(!d->valid || !d->eglContext)
- return;
-
- d->eglContext->swapBuffers();
-}
-
-QColor QGLContext::overlayTransparentColor() const
-{
- return QColor(0, 0, 0); // Invalid color
-}
-
-uint QGLContext::colorIndex(const QColor &c) const
-{
- //### color index doesn't work on egl
- Q_UNUSED(c);
- return 0;
-}
-
-void QGLContext::generateFontDisplayLists(const QFont & fnt, int listBase)
-{
- Q_UNUSED(fnt);
- Q_UNUSED(listBase);
-}
-
-void *QGLContext::getProcAddress(const QString &proc) const
-{
- return (void*)eglGetProcAddress(reinterpret_cast<const char *>(proc.toLatin1().data()));
-}
-
-void QGLWidget::setMouseTracking(bool enable)
-{
- QWidget::setMouseTracking(enable);
-}
-
-
void QGLWidget::resizeEvent(QResizeEvent *)
{
Q_D(QGLWidget);
@@ -232,124 +154,75 @@ void QGLWidget::updateOverlayGL()
//handle overlay
}
-void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
+bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual)
{
- Q_D(QGLWidget);
- if (context == 0) {
- qWarning("QGLWidget::setContext: Cannot set null context");
- return;
- }
- if (!context->deviceIsPixmap() && context->device() != this) {
- qWarning("QGLWidget::setContext: Context must refer to this widget");
- return;
- }
-
- if (d->glcx)
- d->glcx->doneCurrent();
- QGLContext* oldcx = d->glcx;
- d->glcx = context;
-
- if (parentWidget()) {
- // force creation of delay-created widgets
- parentWidget()->winId();
- if (parentWidget()->x11Info().screen() != x11Info().screen())
- d_func()->xinfo = parentWidget()->d_func()->xinfo;
- }
-
- // If the application has set WA_TranslucentBackground and not explicitly set
- // the alpha buffer size to zero, modify the format so it have an alpha channel
- QGLFormat& fmt = d->glcx->d_func()->glFormat;
- const bool useArgbVisual = testAttribute(Qt::WA_TranslucentBackground);
- if (useArgbVisual && fmt.alphaBufferSize() == -1)
- fmt.setAlphaBufferSize(1);
-
- bool createFailed = false;
- if (!d->glcx->isValid()) {
- if (!d->glcx->create(shareContext ? shareContext : oldcx))
- createFailed = true;
- }
- if (createFailed) {
- if (deleteOldContext)
- delete oldcx;
- return;
- }
+ bool foundVisualIsArgb = useArgbVisual;
- if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
- if (deleteOldContext)
- delete oldcx;
- return;
- }
-
- bool visible = isVisible();
- if (visible)
- hide();
-
- XVisualInfo vi;
memset(&vi, 0, sizeof(XVisualInfo));
// Check to see if EGL is suggesting an appropriate visual id:
EGLint nativeVisualId;
- QEglContext* qeglCtx = d->glcx->d_func()->eglContext;
- qeglCtx->configAttrib(EGL_NATIVE_VISUAL_ID, &nativeVisualId);
+ eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisualId);
vi.visualid = nativeVisualId;
if (vi.visualid) {
// EGL has suggested a visual id, so get the rest of the visual info for that id:
XVisualInfo *chosenVisualInfo;
int matchingCount = 0;
- chosenVisualInfo = XGetVisualInfo(x11Info().display(), VisualIDMask, &vi, &matchingCount);
+ chosenVisualInfo = XGetVisualInfo(x11Info.display(), VisualIDMask, &vi, &matchingCount);
if (chosenVisualInfo) {
#if !defined(QT_NO_XRENDER)
if (useArgbVisual) {
// Check to make sure the visual provided by EGL is ARGB
XRenderPictFormat *format;
- format = XRenderFindVisualFormat(x11Info().display(), chosenVisualInfo->visual);
+ format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual);
if (format->type == PictTypeDirect && format->direct.alphaMask) {
- qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);
+// qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid);
+ foundVisualIsArgb = true;
vi = *chosenVisualInfo;
}
else {
qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this is not ARGB",
- nativeVisualId, (int)qeglCtx->config());
+ nativeVisualId, (int)config);
vi.visualid = 0;
}
} else
#endif
{
- qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);
+// qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);
vi = *chosenVisualInfo;
}
XFree(chosenVisualInfo);
}
else {
qWarning("Warning: EGL suggested using X visual ID %d for config %d, but this seems to be invalid!",
- nativeVisualId, (int)qeglCtx->config());
+ nativeVisualId, (int)config);
vi.visualid = 0;
}
}
// If EGL does not know the visual ID, so try to select an appropriate one ourselves, first
// using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo
-
- bool useArgb = context->format().alpha() && !context->deviceIsPixmap();
+
#if !defined(QT_NO_XRENDER)
- if (vi.visualid == 0 && useArgb) {
+ if (vi.visualid == 0 && useArgbVisual) {
// Try to use XRender to find an ARGB visual we can use
- vi.screen = x11Info().screen();
- vi.depth = 32;
+ vi.screen = x11Info.screen();
+ vi.depth = 32; //### We might at some point (soon) get ARGB4444
vi.c_class = TrueColor;
XVisualInfo *matchingVisuals;
int matchingCount = 0;
- matchingVisuals = XGetVisualInfo(x11Info().display(),
+ matchingVisuals = XGetVisualInfo(x11Info.display(),
VisualScreenMask|VisualDepthMask|VisualClassMask,
&vi, &matchingCount);
for (int i = 0; i < matchingCount; ++i) {
XRenderPictFormat *format;
- format = XRenderFindVisualFormat(x11Info().display(), matchingVisuals[i].visual);
+ format = XRenderFindVisualFormat(x11Info.display(), matchingVisuals[i].visual);
if (format->type == PictTypeDirect && format->direct.alphaMask) {
vi = matchingVisuals[i];
- qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid);
+ foundVisualIsArgb = true;
+// qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid);
break;
}
}
@@ -359,25 +232,26 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
if (vi.visualid == 0) {
EGLint depth;
- qeglCtx->configAttrib(EGL_BUFFER_SIZE, &depth);
+ eglGetConfigAttrib(display, config, EGL_BUFFER_SIZE, &depth);
int err;
- err = XMatchVisualInfo(x11Info().display(), x11Info().screen(), depth, TrueColor, &vi);
+ err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
if (err == 0) {
qWarning("Warning: Can't find an X visual which matches the EGL config(%d)'s depth (%d)!",
- (int)qeglCtx->config(), depth);
- depth = x11Info().depth();
- err = XMatchVisualInfo(x11Info().display(), x11Info().screen(), depth, TrueColor, &vi);
+ (int)config, depth);
+ depth = x11Info.depth();
+ err = XMatchVisualInfo(x11Info.display(), x11Info.screen(), depth, TrueColor, &vi);
if (err == 0) {
qWarning("Error: Couldn't get any matching X visual!");
- return;
+ return false;
} else
qWarning(" - Falling back to X11 suggested depth (%d)", depth);
- } else
- qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth);
+ }
+// else
+// qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth);
// Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-(
- if (useArgb)
- useArgb = vi.depth == 32;
+ if (useArgbVisual)
+ foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444
}
// qDebug("Visual Info:");
@@ -390,6 +264,65 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
// qDebug(" depth=%d", vi.depth);
// qDebug(" screen=%d", vi.screen);
// qDebug(" visualid=%d", vi.visualid);
+ return foundVisualIsArgb;
+}
+
+void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, bool deleteOldContext)
+{
+ Q_D(QGLWidget);
+ if (context == 0) {
+ qWarning("QGLWidget::setContext: Cannot set null context");
+ return;
+ }
+ if (!context->deviceIsPixmap() && context->device() != this) {
+ qWarning("QGLWidget::setContext: Context must refer to this widget");
+ return;
+ }
+
+ if (d->glcx)
+ d->glcx->doneCurrent();
+ QGLContext* oldcx = d->glcx;
+ d->glcx = context;
+
+ if (parentWidget()) {
+ // force creation of delay-created widgets
+ parentWidget()->winId();
+ if (parentWidget()->x11Info().screen() != x11Info().screen())
+ d_func()->xinfo = parentWidget()->d_func()->xinfo;
+ }
+
+ // If the application has set WA_TranslucentBackground and not explicitly set
+ // the alpha buffer size to zero, modify the format so it have an alpha channel
+ QGLFormat& fmt = d->glcx->d_func()->glFormat;
+ const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground);
+ if (tryArgbVisual && fmt.alphaBufferSize() == -1)
+ fmt.setAlphaBufferSize(1);
+
+ bool createFailed = false;
+ if (!d->glcx->isValid()) {
+ if (!d->glcx->create(shareContext ? shareContext : oldcx))
+ createFailed = true;
+ }
+ if (createFailed) {
+ if (deleteOldContext)
+ delete oldcx;
+ return;
+ }
+
+ if (d->glcx->windowCreated() || d->glcx->deviceIsPixmap()) {
+ if (deleteOldContext)
+ delete oldcx;
+ return;
+ }
+
+ bool visible = isVisible();
+ if (visible)
+ hide();
+
+ XVisualInfo vi;
+ QEglContext *eglContext = d->glcx->d_func()->eglContext;
+ bool usingArgbVisual = qt_egl_setup_x11_visual(vi, eglContext->display(), eglContext->config(),
+ x11Info(), tryArgbVisual);
XSetWindowAttributes a;
@@ -402,7 +335,7 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
a.border_pixel = colmap.pixel(Qt::black);
unsigned int valueMask = CWBackPixel|CWBorderPixel;
- if(useArgb) {
+ if (usingArgbVisual) {
a.colormap = XCreateColormap(x11Info().display(), p, vi.visual, AllocNone);
valueMask |= CWColormap;
}
@@ -418,9 +351,11 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
// Create the EGL surface to draw into.
- if (!d->glcx->d_func()->eglContext->createSurface(this)) {
- delete d->glcx->d_func()->eglContext;
- d->glcx->d_func()->eglContext = 0;
+ QGLContextPrivate *ctxpriv = d->glcx->d_func();
+ ctxpriv->eglSurface = ctxpriv->eglContext->createSurface(this);
+ if (ctxpriv->eglSurface == EGL_NO_SURFACE) {
+ delete ctxpriv->eglContext;
+ ctxpriv->eglContext = 0;
return;
}
@@ -445,11 +380,6 @@ void QGLWidgetPrivate::init(QGLContext *context, const QGLWidget* shareWidget)
}
}
-bool QGLWidgetPrivate::renderCxPm(QPixmap*)
-{
- return false;
-}
-
void QGLWidgetPrivate::cleanupColormaps()
{
}
@@ -470,7 +400,14 @@ void QGLExtensions::init()
if (init_done)
return;
init_done = true;
+
+ // We need a context current to initialize the extensions.
+ QGLWidget tmpWidget;
+ tmpWidget.makeCurrent();
+
init_extensions();
+
+ tmpWidget.doneCurrent();
}
// Re-creates the EGL surface if the window ID has changed or if force is true
@@ -482,18 +419,137 @@ void QGLWidgetPrivate::recreateEglSurface(bool force)
if ( force || (currentId != eglSurfaceWindowId) ) {
// The window id has changed so we need to re-create the EGL surface
- if (!glcx->d_func()->eglContext->recreateSurface(q))
+ QEglContext *ctx = glcx->d_func()->eglContext;
+ EGLSurface surface = glcx->d_func()->eglSurface;
+ if (surface != EGL_NO_SURFACE)
+ ctx->destroySurface(surface); // Will force doneCurrent() if nec.
+ surface = ctx->createSurface(q);
+ if (surface == EGL_NO_SURFACE)
qWarning("Error creating EGL window surface: 0x%x", eglGetError());
+ glcx->d_func()->eglSurface = surface;
eglSurfaceWindowId = currentId;
}
}
+// Selects which configs should be used
+EGLConfig Q_OPENGL_EXPORT qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly)
+{
+ // Cache the configs we select as they wont change:
+ static EGLConfig roPixmapRGBConfig = 0;
+ static EGLConfig roPixmapRGBAConfig = 0;
+ static EGLConfig rwPixmapRGBConfig = 0;
+ static EGLConfig rwPixmapRGBAConfig = 0;
+
+ EGLConfig* targetConfig;
+
+ if (hasAlpha) {
+ if (readOnly)
+ targetConfig = &roPixmapRGBAConfig;
+ else
+ targetConfig = &rwPixmapRGBAConfig;
+ }
+ else {
+ if (readOnly)
+ targetConfig = &roPixmapRGBConfig;
+ else
+ targetConfig = &rwPixmapRGBConfig;
+ }
+
+ if (*targetConfig == 0) {
+ QEglProperties configAttribs;
+ configAttribs.setValue(EGL_SURFACE_TYPE, EGL_PIXMAP_BIT);
+ configAttribs.setRenderableType(QEgl::OpenGL);
+ if (hasAlpha)
+ configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
+ else
+ configAttribs.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
+
+ // If this is going to be a render target, it needs to have a depth, stencil & sample buffer
+ if (!readOnly) {
+ configAttribs.setValue(EGL_DEPTH_SIZE, 1);
+ configAttribs.setValue(EGL_STENCIL_SIZE, 1);
+ configAttribs.setValue(EGL_SAMPLE_BUFFERS, 1);
+ }
+
+ EGLint configCount = 0;
+ do {
+ eglChooseConfig(QEglContext::defaultDisplay(0), configAttribs.properties(), targetConfig, 1, &configCount);
+ if (configCount > 0) {
+ // Got one
+ qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB") << (readOnly ? "readonly" : "target" )
+ << "config (" << int(*targetConfig) << ") to create a pixmap surface:";
+
+// QEglProperties configProps(*targetConfig);
+// qDebug() << configProps.toString();
+ break;
+ }
+ qWarning("choosePixmapConfig() - No suitible config found, reducing requirements");
+ } while (configAttribs.reduceConfiguration());
+ }
+
+ if (*targetConfig == 0)
+ qWarning("choosePixmapConfig() - Couldn't find a suitable config");
+
+ return *targetConfig;
+}
+
+bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly)
+{
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData* pixmapData = static_cast<QX11PixmapData*>(pmd);
+
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+
+ EGLConfig pixmapConfig = qt_chooseEGLConfigForPixmap(hasAlpha, readOnly);
+
+ QEglProperties pixmapAttribs;
+
+ // If the pixmap can't be bound to a texture, it's pretty useless
+ pixmapAttribs.setValue(EGL_TEXTURE_TARGET, EGL_TEXTURE_2D);
+ if (hasAlpha)
+ pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA);
+ else
+ pixmapAttribs.setValue(EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB);
+
+ EGLSurface pixmapSurface;
+ pixmapSurface = eglCreatePixmapSurface(QEglContext::defaultDisplay(0),
+ pixmapConfig,
+ (EGLNativePixmapType) pixmapData->handle(),
+ pixmapAttribs.properties());
+// qDebug("qt_createEGLSurfaceForPixmap() created surface 0x%x for pixmap 0x%x",
+// pixmapSurface, pixmapData->handle());
+ if (pixmapSurface == EGL_NO_SURFACE) {
+ qWarning() << "Failed to create a pixmap surface using config" << (int)pixmapConfig
+ << ":" << QEglContext::errorString(eglGetError());
+ return false;
+ }
+
+ static bool doneOnce = false;
+ if (!doneOnce) {
+ // Make sure QGLTextureCache is instanciated so it can install cleanup hooks
+ // which cleanup the EGL surface.
+ QGLTextureCache::instance();
+ doneOnce = true;
+ }
+
+ Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure!
+ pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmapData); // Make sure the cleanup hook gets called
+
+ return true;
+}
+
-QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key, bool canInvert)
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key,
+ QGLContext::BindOptions options)
{
Q_Q(QGLContext);
+ // The EGL texture_from_pixmap has no facility to invert the y coordinate
+ if (!(options & QGLContext::CanFlipNativePixmapBindOption))
+ return 0;
+
Q_ASSERT(pd->classId() == QPixmapData::X11Class);
static bool checkedForTFP = false;
@@ -525,101 +581,32 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, cons
destroyGlSurfaceForPixmap(pixmapData);
}
- EGLint pixmapAttribs[] = {
- EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
- EGL_TEXTURE_FORMAT, hasAlpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB,
- EGL_NONE
- };
- Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure!
- if (pixmapData->gl_surface == 0)
- pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
- EGLSurface pixmapSurface = (EGLSurface)pixmapData->gl_surface;
- static EGLConfig pixmapRGBConfig = 0;
- static EGLConfig pixmapRGBAConfig = 0;
-
- // Check to see if we need to find a config
- if ((hasAlpha && !pixmapRGBAConfig) || (!hasAlpha && !pixmapRGBConfig) ) {
- const EGLint configAttribs[] = {
- EGL_SURFACE_TYPE, EGL_PIXMAP_BIT,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_DEPTH_SIZE, 0,
- hasAlpha ? EGL_BIND_TO_TEXTURE_RGBA : EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE,
- EGL_NONE
- };
-
- EGLint configCount = 0;
- eglChooseConfig(eglContext->display(), configAttribs, 0, 256, &configCount);
- if (configCount == 0) {
- haveTFP = false;
- qWarning("bindTextureFromNativePixmap() - Couldn't find a suitable config");
- return 0;
- }
-
- EGLConfig *configList = new EGLConfig[configCount];
- eglChooseConfig(eglContext->display(), configAttribs, configList, configCount, &configCount);
- Q_ASSERT(configCount);
-
- // Try to create a pixmap surface for each config until one works
- for (int i = 0; i < configCount; ++i) {
- pixmapSurface = eglCreatePixmapSurface(eglContext->display(), configList[i],
- (EGLNativePixmapType) pixmapData->handle(),
- pixmapAttribs);
- if (pixmapSurface != EGL_NO_SURFACE) {
- // Got one!
- qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB")
- << "config (" << int(configList[i]) << ") to create a pixmap surface";
- if (hasAlpha)
- pixmapRGBAConfig = configList[i];
- else
- pixmapRGBConfig = configList[i];
- pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
- break;
- }
- }
- delete configList;
-
- if ((hasAlpha && !pixmapRGBAConfig) || (!hasAlpha && !pixmapRGBConfig) ) {
- qDebug("Couldn't create a pixmap surface with any of the provided configs");
- haveTFP = false;
- return 0;
- }
- }
-
- if (pixmapSurface == EGL_NO_SURFACE) {
- pixmapSurface = eglCreatePixmapSurface(eglContext->display(),
- hasAlpha? pixmapRGBAConfig : pixmapRGBConfig,
- (EGLNativePixmapType) pixmapData->handle(),
- pixmapAttribs);
- if (pixmapSurface == EGL_NO_SURFACE) {
- qWarning("Failed to create a pixmap surface using config %d",
- (int)(hasAlpha? pixmapRGBAConfig : pixmapRGBConfig));
+ if (pixmapData->gl_surface == 0) {
+ bool success = qt_createEGLSurfaceForPixmap(pixmapData, true);
+ if (!success) {
haveTFP = false;
return 0;
}
- pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
}
- // Make sure the cleanup hook gets called so we can delete the glx pixmap
- pixmapData->is_cached = true;
Q_ASSERT(pixmapData->gl_surface);
GLuint textureId;
glGenTextures(1, &textureId);
- glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);
// bind the egl pixmap surface to a texture
EGLBoolean success;
- success = eglBindTexImage(eglContext->display(), pixmapSurface, EGL_BACK_BUFFER);
+ success = eglBindTexImage(eglContext->display(), (EGLSurface)pixmapData->gl_surface, EGL_BACK_BUFFER);
if (success == EGL_FALSE) {
qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError());
- eglDestroySurface(eglContext->display(), pixmapSurface);
+ eglDestroySurface(eglContext->display(), (EGLSurface)pixmapData->gl_surface);
pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
haveTFP = false;
return 0;
}
- QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, true);
+ QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, options);
pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
// We assume the cost of bound pixmaps is zero
diff --git a/src/opengl/qglcolormap.cpp b/src/opengl/qglcolormap.cpp
index 0d38ce74a..b86f9e039 100644
--- a/src/opengl/qglcolormap.cpp
+++ b/src/opengl/qglcolormap.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -42,14 +42,14 @@
/*!
\class QGLColormap
\brief The QGLColormap class is used for installing custom colormaps into
- QGLWidgets.
+ a QGLWidget.
\module OpenGL
- \ingroup multimedia
+ \ingroup painting-3D
\ingroup shared
QGLColormap provides a platform independent way of specifying and
- installing indexed colormaps into QGLWidgets. QGLColormap is
+ installing indexed colormaps for a QGLWidget. QGLColormap is
especially useful when using the OpenGL color-index mode.
Under X11 you must use an X server that supports either a \c
@@ -61,7 +61,7 @@
least a \c PseudoColor visual. Note that you may experience
colormap flashing if your X server is running in 8 bit mode.
- Under Windows the size of the colormap is always set to 256
+ The size() of the colormap is always set to 256
colors. Note that under Windows you can also install colormaps
in child widgets.
diff --git a/src/opengl/qglcolormap.h b/src/opengl/qglcolormap.h
index a71b07c10..55969920a 100644
--- a/src/opengl/qglcolormap.h
+++ b/src/opengl/qglcolormap.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/qglextensions.cpp b/src/opengl/qglextensions.cpp
index 68e301dea..c785d8a38 100644
--- a/src/opengl/qglextensions.cpp
+++ b/src/opengl/qglextensions.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -43,6 +43,52 @@
QT_BEGIN_NAMESPACE
+static void *qt_gl_getProcAddress_search
+ (QGLContext *ctx, const char *name1, const char *name2,
+ const char *name3, const char *name4)
+{
+ void *addr;
+
+ addr = ctx->getProcAddress(QLatin1String(name1));
+ if (addr)
+ return addr;
+
+ addr = ctx->getProcAddress(QLatin1String(name2));
+ if (addr)
+ return addr;
+
+ addr = ctx->getProcAddress(QLatin1String(name3));
+ if (addr)
+ return addr;
+
+ if (name4)
+ return ctx->getProcAddress(QLatin1String(name4));
+
+ return 0;
+}
+
+// Search for an extension function starting with the most likely
+// function suffix first, and then trying the other variations.
+#if defined(QT_OPENGL_ES)
+#define qt_gl_getProcAddress(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name, name "OES", name "EXT", name "ARB")
+#define qt_gl_getProcAddressEXT(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "OES", name, name "EXT", name "ARB")
+#define qt_gl_getProcAddressARB(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "OES", name, name "ARB", name "EXT")
+#define qt_gl_getProcAddressOES(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "OES", name, name "EXT", name "ARB")
+#else
+#define qt_gl_getProcAddress(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name, name "ARB", name "EXT", 0)
+#define qt_gl_getProcAddressEXT(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "EXT", name, name "ARB", 0)
+#define qt_gl_getProcAddressARB(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "ARB", name, name "EXT", 0)
+#define qt_gl_getProcAddressOES(ctx,name) \
+ qt_gl_getProcAddress_search((ctx), name "OES", name, name "EXT", name "ARB")
+#endif
+
bool qt_resolve_framebufferobject_extensions(QGLContext *ctx)
{
#if defined(QT_OPENGL_ES_2)
@@ -62,30 +108,32 @@ bool qt_resolve_framebufferobject_extensions(QGLContext *ctx)
}
- glBlitFramebufferEXT = (_glBlitFramebufferEXT) ctx->getProcAddress(QLatin1String("glBlitFramebufferEXT"));
+ glBlitFramebufferEXT = (_glBlitFramebufferEXT) qt_gl_getProcAddressEXT(ctx, "glBlitFramebuffer");
glRenderbufferStorageMultisampleEXT =
- (_glRenderbufferStorageMultisampleEXT) ctx->getProcAddress(QLatin1String("glRenderbufferStorageMultisampleEXT"));
+ (_glRenderbufferStorageMultisampleEXT) qt_gl_getProcAddressEXT(ctx, "glRenderbufferStorageMultisample");
#if !defined(QT_OPENGL_ES_2)
- glIsRenderbuffer = (_glIsRenderbuffer) ctx->getProcAddress(QLatin1String("glIsRenderbufferEXT"));
- glBindRenderbuffer = (_glBindRenderbuffer) ctx->getProcAddress(QLatin1String("glBindRenderbufferEXT"));
- glDeleteRenderbuffers = (_glDeleteRenderbuffers) ctx->getProcAddress(QLatin1String("glDeleteRenderbuffersEXT"));
- glGenRenderbuffers = (_glGenRenderbuffers) ctx->getProcAddress(QLatin1String("glGenRenderbuffersEXT"));
- glRenderbufferStorage = (_glRenderbufferStorage) ctx->getProcAddress(QLatin1String("glRenderbufferStorageEXT"));
+ glIsRenderbuffer = (_glIsRenderbuffer) qt_gl_getProcAddressEXT(ctx, "glIsRenderbuffer");
+ if (!glIsRenderbuffer)
+ return false; // Not much point searching for anything else.
+ glBindRenderbuffer = (_glBindRenderbuffer) qt_gl_getProcAddressEXT(ctx, "glBindRenderbuffer");
+ glDeleteRenderbuffers = (_glDeleteRenderbuffers) qt_gl_getProcAddressEXT(ctx, "glDeleteRenderbuffers");
+ glGenRenderbuffers = (_glGenRenderbuffers) qt_gl_getProcAddressEXT(ctx, "glGenRenderbuffers");
+ glRenderbufferStorage = (_glRenderbufferStorage) qt_gl_getProcAddressEXT(ctx, "glRenderbufferStorage");
glGetRenderbufferParameteriv =
- (_glGetRenderbufferParameteriv) ctx->getProcAddress(QLatin1String("glGetRenderbufferParameterivEXT"));
- glIsFramebuffer = (_glIsFramebuffer) ctx->getProcAddress(QLatin1String("glIsFramebufferEXT"));
- glBindFramebuffer = (_glBindFramebuffer) ctx->getProcAddress(QLatin1String("glBindFramebufferEXT"));
- glDeleteFramebuffers = (_glDeleteFramebuffers) ctx->getProcAddress(QLatin1String("glDeleteFramebuffersEXT"));
- glGenFramebuffers = (_glGenFramebuffers) ctx->getProcAddress(QLatin1String("glGenFramebuffersEXT"));
- glCheckFramebufferStatus = (_glCheckFramebufferStatus) ctx->getProcAddress(QLatin1String("glCheckFramebufferStatusEXT"));
- glFramebufferTexture2D = (_glFramebufferTexture2D) ctx->getProcAddress(QLatin1String("glFramebufferTexture2DEXT"));
- glFramebufferRenderbuffer = (_glFramebufferRenderbuffer) ctx->getProcAddress(QLatin1String("glFramebufferRenderbufferEXT"));
+ (_glGetRenderbufferParameteriv) qt_gl_getProcAddressEXT(ctx, "glGetRenderbufferParameteriv");
+ glIsFramebuffer = (_glIsFramebuffer) qt_gl_getProcAddressEXT(ctx, "glIsFramebuffer");
+ glBindFramebuffer = (_glBindFramebuffer) qt_gl_getProcAddressEXT(ctx, "glBindFramebuffer");
+ glDeleteFramebuffers = (_glDeleteFramebuffers) qt_gl_getProcAddressEXT(ctx, "glDeleteFramebuffers");
+ glGenFramebuffers = (_glGenFramebuffers) qt_gl_getProcAddressEXT(ctx, "glGenFramebuffers");
+ glCheckFramebufferStatus = (_glCheckFramebufferStatus) qt_gl_getProcAddressEXT(ctx, "glCheckFramebufferStatus");
+ glFramebufferTexture2D = (_glFramebufferTexture2D) qt_gl_getProcAddressEXT(ctx, "glFramebufferTexture2D");
+ glFramebufferRenderbuffer = (_glFramebufferRenderbuffer) qt_gl_getProcAddressEXT(ctx, "glFramebufferRenderbuffer");
glGetFramebufferAttachmentParameteriv =
- (_glGetFramebufferAttachmentParameteriv) ctx->getProcAddress(QLatin1String("glGetFramebufferAttachmentParameterivEXT"));
- glGenerateMipmap = (_glGenerateMipmap) ctx->getProcAddress(QLatin1String("glGenerateMipmapEXT"));
+ (_glGetFramebufferAttachmentParameteriv) qt_gl_getProcAddressEXT(ctx, "glGetFramebufferAttachmentParameteriv");
+ glGenerateMipmap = (_glGenerateMipmap) qt_gl_getProcAddressEXT(ctx, "glGenerateMipmap");
- return glIsRenderbuffer;
+ return glIsRenderbuffer != 0;
#else
return true;
#endif
@@ -151,13 +199,13 @@ bool qt_resolve_buffer_extensions(QGLContext *ctx)
return true;
#if !defined(QT_OPENGL_ES_2)
- glBindBuffer = (_glBindBuffer) ctx->getProcAddress(QLatin1String("glBindBufferARB"));
- glDeleteBuffers = (_glDeleteBuffers) ctx->getProcAddress(QLatin1String("glDeleteBuffersARB"));
- glGenBuffers = (_glGenBuffers) ctx->getProcAddress(QLatin1String("glGenBuffersARB"));
- glBufferData = (_glBufferData) ctx->getProcAddress(QLatin1String("glBufferDataARB"));
+ glBindBuffer = (_glBindBuffer) qt_gl_getProcAddressARB(ctx, "glBindBuffer");
+ glDeleteBuffers = (_glDeleteBuffers) qt_gl_getProcAddressARB(ctx, "glDeleteBuffers");
+ glGenBuffers = (_glGenBuffers) qt_gl_getProcAddressARB(ctx, "glGenBuffers");
+ glBufferData = (_glBufferData) qt_gl_getProcAddressARB(ctx, "glBufferData");
#endif
- glMapBufferARB = (_glMapBufferARB) ctx->getProcAddress(QLatin1String("glMapBufferARB"));
- glUnmapBufferARB = (_glUnmapBufferARB) ctx->getProcAddress(QLatin1String("glUnmapBufferARB"));
+ glMapBufferARB = (_glMapBufferARB) qt_gl_getProcAddressARB(ctx, "glMapBuffer");
+ glUnmapBufferARB = (_glUnmapBufferARB) qt_gl_getProcAddressARB(ctx, "glUnmapBuffer");
return glMapBufferARB
&& glUnmapBufferARB
@@ -175,10 +223,10 @@ bool qt_resolve_glsl_extensions(QGLContext *ctx)
#if defined(QT_OPENGL_ES_2)
// The GLSL shader functions are always present in OpenGL/ES 2.0.
// The only exceptions are glGetProgramBinaryOES and glProgramBinaryOES.
- if (!QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glslResolved) {
+ if (!QGLContextPrivate::extensionFuncs(ctx).qt_glslResolved) {
glGetProgramBinaryOES = (_glGetProgramBinaryOES) ctx->getProcAddress(QLatin1String("glGetProgramBinaryOES"));
glProgramBinaryOES = (_glProgramBinaryOES) ctx->getProcAddress(QLatin1String("glProgramBinaryOES"));
- QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glslResolved = true;
+ QGLContextPrivate::extensionFuncs(ctx).qt_glslResolved = true;
}
return true;
#else
@@ -343,8 +391,9 @@ bool qt_resolve_version_2_0_functions(QGLContext *ctx)
if (glStencilOpSeparate)
return gl2supported;
+ glBlendColor = (_glBlendColor) ctx->getProcAddress(QLatin1String("glBlendColor"));
glStencilOpSeparate = (_glStencilOpSeparate) ctx->getProcAddress(QLatin1String("glStencilOpSeparate"));
- if (!glStencilOpSeparate)
+ if (!glBlendColor || !glStencilOpSeparate)
gl2supported = false;
return gl2supported;
diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h
index b03fdfae6..351076523 100644
--- a/src/opengl/qglextensions_p.h
+++ b/src/opengl/qglextensions_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -152,6 +152,7 @@ typedef void (APIENTRY *_glActiveStencilFaceEXT) (GLenum );
// Needed for GL2 engine:
typedef void (APIENTRY *_glStencilOpSeparate) (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
typedef void (APIENTRY *_glActiveTexture) (GLenum);
+typedef void (APIENTRY *_glBlendColor) (GLclampf, GLclampf, GLclampf, GLclampf);
// EXT_GL_framebuffer_object
@@ -247,6 +248,7 @@ struct QGLExtensionFuncs
// Extras for GL2 engine:
qt_glActiveTexture = 0;
qt_glStencilOpSeparate = 0;
+ qt_glBlendColor = 0;
qt_glActiveStencilFaceEXT = 0;
qt_glMultiTexCoord4f = 0;
@@ -360,6 +362,8 @@ struct QGLExtensionFuncs
// Extras needed for GL2 engine:
_glActiveTexture qt_glActiveTexture;
_glStencilOpSeparate qt_glStencilOpSeparate;
+ _glBlendColor qt_glBlendColor;
+
#endif
// FBOs
@@ -410,6 +414,18 @@ struct QGLExtensionFuncs
#define GL_BGRA 0x80E1
#endif
+#ifndef GL_RGB16
+#define GL_RGB16 32852
+#endif
+
+#ifndef GL_UNSIGNED_SHORT_5_6_5
+#define GL_UNSIGNED_SHORT_5_6_5 33635
+#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
@@ -562,6 +578,10 @@ struct QGLExtensionFuncs
#endif
#ifndef GL_VERSION_1_4
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
#define GL_INCR_WRAP 0x8507
#define GL_DECR_WRAP 0x8508
#endif
@@ -597,114 +617,115 @@ struct QGLExtensionFuncs
#if !defined(QT_OPENGL_ES_2)
-#define glProgramStringARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glProgramStringARB
-#define glBindProgramARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindProgramARB
-#define glDeleteProgramsARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteProgramsARB
-#define glGenProgramsARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenProgramsARB
-#define glProgramLocalParameter4fvARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glProgramLocalParameter4fvARB
+#define glProgramStringARB QGLContextPrivate::extensionFuncs(ctx).qt_glProgramStringARB
+#define glBindProgramARB QGLContextPrivate::extensionFuncs(ctx).qt_glBindProgramARB
+#define glDeleteProgramsARB QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteProgramsARB
+#define glGenProgramsARB QGLContextPrivate::extensionFuncs(ctx).qt_glGenProgramsARB
+#define glProgramLocalParameter4fvARB QGLContextPrivate::extensionFuncs(ctx).qt_glProgramLocalParameter4fvARB
-#define glActiveStencilFaceEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glActiveStencilFaceEXT
+#define glActiveStencilFaceEXT QGLContextPrivate::extensionFuncs(ctx).qt_glActiveStencilFaceEXT
-#define glMultiTexCoord4f QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glMultiTexCoord4f
+#define glMultiTexCoord4f QGLContextPrivate::extensionFuncs(ctx).qt_glMultiTexCoord4f
-#define glActiveTexture QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glActiveTexture
+#define glActiveTexture QGLContextPrivate::extensionFuncs(ctx).qt_glActiveTexture
#endif // !defined(QT_OPENGL_ES_2)
// FBOs
#if !defined(QT_OPENGL_ES_2)
-#define glIsRenderbuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsRenderbuffer
-#define glBindRenderbuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindRenderbuffer
-#define glDeleteRenderbuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteRenderbuffers
-#define glGenRenderbuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenRenderbuffers
-#define glRenderbufferStorage QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glRenderbufferStorage
-#define glGetRenderbufferParameteriv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetRenderbufferParameteriv
-#define glIsFramebuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsFramebuffer
-#define glBindFramebuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindFramebuffer
-#define glDeleteFramebuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteFramebuffers
-#define glGenFramebuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenFramebuffers
-#define glCheckFramebufferStatus QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCheckFramebufferStatus
-#define glFramebufferTexture2D QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferTexture2D
-#define glFramebufferRenderbuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glFramebufferRenderbuffer
-#define glGetFramebufferAttachmentParameteriv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetFramebufferAttachmentParameteriv
-#define glGenerateMipmap QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenerateMipmap
+#define glIsRenderbuffer QGLContextPrivate::extensionFuncs(ctx).qt_glIsRenderbuffer
+#define glBindRenderbuffer QGLContextPrivate::extensionFuncs(ctx).qt_glBindRenderbuffer
+#define glDeleteRenderbuffers QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteRenderbuffers
+#define glGenRenderbuffers QGLContextPrivate::extensionFuncs(ctx).qt_glGenRenderbuffers
+#define glRenderbufferStorage QGLContextPrivate::extensionFuncs(ctx).qt_glRenderbufferStorage
+#define glGetRenderbufferParameteriv QGLContextPrivate::extensionFuncs(ctx).qt_glGetRenderbufferParameteriv
+#define glIsFramebuffer QGLContextPrivate::extensionFuncs(ctx).qt_glIsFramebuffer
+#define glBindFramebuffer QGLContextPrivate::extensionFuncs(ctx).qt_glBindFramebuffer
+#define glDeleteFramebuffers QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteFramebuffers
+#define glGenFramebuffers QGLContextPrivate::extensionFuncs(ctx).qt_glGenFramebuffers
+#define glCheckFramebufferStatus QGLContextPrivate::extensionFuncs(ctx).qt_glCheckFramebufferStatus
+#define glFramebufferTexture2D QGLContextPrivate::extensionFuncs(ctx).qt_glFramebufferTexture2D
+#define glFramebufferRenderbuffer QGLContextPrivate::extensionFuncs(ctx).qt_glFramebufferRenderbuffer
+#define glGetFramebufferAttachmentParameteriv QGLContextPrivate::extensionFuncs(ctx).qt_glGetFramebufferAttachmentParameteriv
+#define glGenerateMipmap QGLContextPrivate::extensionFuncs(ctx).qt_glGenerateMipmap
#endif // QT_OPENGL_ES_2
-#define glBlitFramebufferEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBlitFramebufferEXT
-#define glRenderbufferStorageMultisampleEXT QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glRenderbufferStorageMultisampleEXT
+#define glBlitFramebufferEXT QGLContextPrivate::extensionFuncs(ctx).qt_glBlitFramebufferEXT
+#define glRenderbufferStorageMultisampleEXT QGLContextPrivate::extensionFuncs(ctx).qt_glRenderbufferStorageMultisampleEXT
// Buffer objects
#if !defined(QT_OPENGL_ES_2)
-#define glBindBuffer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindBuffer
-#define glDeleteBuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteBuffers
-#define glGenBuffers QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGenBuffers
-#define glBufferData QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBufferData
+#define glBindBuffer QGLContextPrivate::extensionFuncs(ctx).qt_glBindBuffer
+#define glDeleteBuffers QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteBuffers
+#define glGenBuffers QGLContextPrivate::extensionFuncs(ctx).qt_glGenBuffers
+#define glBufferData QGLContextPrivate::extensionFuncs(ctx).qt_glBufferData
#endif
-#define glMapBufferARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glMapBufferARB
-#define glUnmapBufferARB QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUnmapBufferARB
+#define glMapBufferARB QGLContextPrivate::extensionFuncs(ctx).qt_glMapBufferARB
+#define glUnmapBufferARB QGLContextPrivate::extensionFuncs(ctx).qt_glUnmapBufferARB
// GLSL
#if !defined(QT_OPENGL_ES_2)
-#define glCreateShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCreateShader
-#define glShaderSource QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glShaderSource
-#define glShaderBinary QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glShaderBinary
-#define glCompileShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCompileShader
-#define glDeleteShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteShader
-#define glIsShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsShader
-
-#define glCreateProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glCreateProgram
-#define glAttachShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glAttachShader
-#define glDetachShader QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDetachShader
-#define glLinkProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glLinkProgram
-#define glUseProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUseProgram
-#define glDeleteProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDeleteProgram
-#define glIsProgram QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glIsProgram
-
-#define glGetShaderInfoLog QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderInfoLog
-#define glGetShaderiv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderiv
-#define glGetShaderSource QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetShaderSource
-#define glGetProgramiv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetProgramiv
-#define glGetProgramInfoLog QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetProgramInfoLog
-
-#define glGetUniformLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetUniformLocation
-#define glUniform4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform4fv
-#define glUniform3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform3fv
-#define glUniform2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform2fv
-#define glUniform1fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1fv
-#define glUniform1i QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1i
-#define glUniform1iv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniform1iv
-#define glUniformMatrix2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix2fv
-#define glUniformMatrix3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix3fv
-#define glUniformMatrix4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix4fv
-#define glUniformMatrix2x3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix2x3fv
-#define glUniformMatrix2x4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix2x4fv
-#define glUniformMatrix3x2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix3x2fv
-#define glUniformMatrix3x4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix3x4fv
-#define glUniformMatrix4x2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix4x2fv
-#define glUniformMatrix4x3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glUniformMatrix4x3fv
-
-#define glBindAttribLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glBindAttribLocation
-#define glGetAttribLocation QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetAttribLocation
-#define glVertexAttrib1fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib1fv
-#define glVertexAttrib2fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib2fv
-#define glVertexAttrib3fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib3fv
-#define glVertexAttrib4fv QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttrib4fv
-#define glVertexAttribPointer QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glVertexAttribPointer
-#define glDisableVertexAttribArray QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glDisableVertexAttribArray
-#define glEnableVertexAttribArray QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glEnableVertexAttribArray
+#define glCreateShader QGLContextPrivate::extensionFuncs(ctx).qt_glCreateShader
+#define glShaderSource QGLContextPrivate::extensionFuncs(ctx).qt_glShaderSource
+#define glShaderBinary QGLContextPrivate::extensionFuncs(ctx).qt_glShaderBinary
+#define glCompileShader QGLContextPrivate::extensionFuncs(ctx).qt_glCompileShader
+#define glDeleteShader QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteShader
+#define glIsShader QGLContextPrivate::extensionFuncs(ctx).qt_glIsShader
+
+#define glCreateProgram QGLContextPrivate::extensionFuncs(ctx).qt_glCreateProgram
+#define glAttachShader QGLContextPrivate::extensionFuncs(ctx).qt_glAttachShader
+#define glDetachShader QGLContextPrivate::extensionFuncs(ctx).qt_glDetachShader
+#define glLinkProgram QGLContextPrivate::extensionFuncs(ctx).qt_glLinkProgram
+#define glUseProgram QGLContextPrivate::extensionFuncs(ctx).qt_glUseProgram
+#define glDeleteProgram QGLContextPrivate::extensionFuncs(ctx).qt_glDeleteProgram
+#define glIsProgram QGLContextPrivate::extensionFuncs(ctx).qt_glIsProgram
+
+#define glGetShaderInfoLog QGLContextPrivate::extensionFuncs(ctx).qt_glGetShaderInfoLog
+#define glGetShaderiv QGLContextPrivate::extensionFuncs(ctx).qt_glGetShaderiv
+#define glGetShaderSource QGLContextPrivate::extensionFuncs(ctx).qt_glGetShaderSource
+#define glGetProgramiv QGLContextPrivate::extensionFuncs(ctx).qt_glGetProgramiv
+#define glGetProgramInfoLog QGLContextPrivate::extensionFuncs(ctx).qt_glGetProgramInfoLog
+
+#define glGetUniformLocation QGLContextPrivate::extensionFuncs(ctx).qt_glGetUniformLocation
+#define glUniform4fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniform4fv
+#define glUniform3fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniform3fv
+#define glUniform2fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniform2fv
+#define glUniform1fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniform1fv
+#define glUniform1i QGLContextPrivate::extensionFuncs(ctx).qt_glUniform1i
+#define glUniform1iv QGLContextPrivate::extensionFuncs(ctx).qt_glUniform1iv
+#define glUniformMatrix2fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix2fv
+#define glUniformMatrix3fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix3fv
+#define glUniformMatrix4fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix4fv
+#define glUniformMatrix2x3fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix2x3fv
+#define glUniformMatrix2x4fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix2x4fv
+#define glUniformMatrix3x2fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix3x2fv
+#define glUniformMatrix3x4fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix3x4fv
+#define glUniformMatrix4x2fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix4x2fv
+#define glUniformMatrix4x3fv QGLContextPrivate::extensionFuncs(ctx).qt_glUniformMatrix4x3fv
+
+#define glBindAttribLocation QGLContextPrivate::extensionFuncs(ctx).qt_glBindAttribLocation
+#define glGetAttribLocation QGLContextPrivate::extensionFuncs(ctx).qt_glGetAttribLocation
+#define glVertexAttrib1fv QGLContextPrivate::extensionFuncs(ctx).qt_glVertexAttrib1fv
+#define glVertexAttrib2fv QGLContextPrivate::extensionFuncs(ctx).qt_glVertexAttrib2fv
+#define glVertexAttrib3fv QGLContextPrivate::extensionFuncs(ctx).qt_glVertexAttrib3fv
+#define glVertexAttrib4fv QGLContextPrivate::extensionFuncs(ctx).qt_glVertexAttrib4fv
+#define glVertexAttribPointer QGLContextPrivate::extensionFuncs(ctx).qt_glVertexAttribPointer
+#define glDisableVertexAttribArray QGLContextPrivate::extensionFuncs(ctx).qt_glDisableVertexAttribArray
+#define glEnableVertexAttribArray QGLContextPrivate::extensionFuncs(ctx).qt_glEnableVertexAttribArray
#else // QT_OPENGL_ES_2
-#define glGetProgramBinaryOES QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glGetProgramBinaryOES
-#define glProgramBinaryOES QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glProgramBinaryOES
+#define glGetProgramBinaryOES QGLContextPrivate::extensionFuncs(ctx).qt_glGetProgramBinaryOES
+#define glProgramBinaryOES QGLContextPrivate::extensionFuncs(ctx).qt_glProgramBinaryOES
#endif // QT_OPENGL_ES_2
#if !defined(QT_OPENGL_ES_2)
-#define glStencilOpSeparate QGLContextPrivate::qt_get_extension_funcs(ctx).qt_glStencilOpSeparate
+#define glStencilOpSeparate QGLContextPrivate::extensionFuncs(ctx).qt_glStencilOpSeparate
+#define glBlendColor QGLContextPrivate::extensionFuncs(ctx).qt_glBlendColor
#endif
#if defined(QT_OPENGL_ES_2)
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index f48c18ddc..d0297c98f 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,26 +21,26 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qglframebufferobject.h"
+#include "qglframebufferobject_p.h"
#include <qdebug.h>
#include <private/qgl_p.h>
@@ -63,8 +64,14 @@ QT_BEGIN_NAMESPACE
extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
-#define QGL_FUNC_CONTEXT QGLContext *ctx = d_ptr->ctx;
+#define QGL_FUNC_CONTEXT const QGLContext *ctx = d_ptr->fbo_guard.context();
+#define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context();
+#ifndef QT_NO_DEBUG
+#define QT_RESET_GLERROR() \
+{ \
+ while (glGetError() != GL_NO_ERROR) {} \
+}
#define QT_CHECK_GLERROR() \
{ \
GLenum err = glGetError(); \
@@ -73,15 +80,10 @@ extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
__FILE__, __LINE__, (int)err); \
} \
}
-
-class QGLFramebufferObjectFormatPrivate
-{
-public:
- int samples;
- QGLFramebufferObject::Attachment attachment;
- GLenum target;
- GLenum internal_format;
-};
+#else
+#define QT_RESET_GLERROR() {}
+#define QT_CHECK_GLERROR() {}
+#endif
/*!
\class QGLFramebufferObjectFormat
@@ -90,14 +92,14 @@ public:
\since 4.6
- \ingroup multimedia
+ \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 setInternalFormat() Internal format.\endlink
+ \i \link setInternalTextureFormat() Internal texture format.\endlink
\endlist
Note that the desired attachments or number of samples per pixels might not
@@ -109,38 +111,33 @@ public:
*/
/*!
- Creates a QGLFramebufferObjectFormat object with properties specifying
- the format of an OpenGL framebuffer object.
-
- A multisample framebuffer object is specified by setting \a samples
- to a value different from zero. 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.
+ \internal
+*/
+void QGLFramebufferObjectFormat::detach()
+{
+ if (d->ref != 1) {
+ QGLFramebufferObjectFormatPrivate *newd
+ = new QGLFramebufferObjectFormatPrivate(d);
+ if (!d->ref.deref())
+ delete d;
+ d = newd;
+ }
+}
- For multisample framebuffer objects a color render buffer is created,
- otherwise a texture with the texture target \a target is created.
- The color render buffer or texture will have the internal format
- \a internalFormat, and will be bound to the \c GL_COLOR_ATTACHMENT0
- attachment in the framebuffer object.
+/*!
+ Creates a QGLFramebufferObjectFormat object for specifying
+ the format of an OpenGL framebuffer object.
- The \a attachment parameter describes the depth/stencil buffer
- configuration.
+ 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(), target(), internalFormat()
+ \sa samples(), attachment(), target(), internalTextureFormat()
*/
-QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(int samples,
- QGLFramebufferObject::Attachment attachment,
- GLenum target,
- GLenum internalFormat)
+QGLFramebufferObjectFormat::QGLFramebufferObjectFormat()
{
d = new QGLFramebufferObjectFormatPrivate;
- d->samples = samples;
- d->attachment = attachment;
- d->target = target;
- d->internal_format = internalFormat;
}
/*!
@@ -149,8 +146,8 @@ QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(int samples,
QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other)
{
- d = new QGLFramebufferObjectFormatPrivate;
- *d = *other.d;
+ d = other.d;
+ d->ref.ref();
}
/*!
@@ -159,7 +156,12 @@ QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjec
QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other)
{
- *d = *other.d;
+ if (d != other.d) {
+ other.d->ref.ref();
+ if (!d->ref.deref())
+ delete d;
+ d = other.d;
+ }
return *this;
}
@@ -168,24 +170,33 @@ QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFrame
*/
QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
{
- delete d;
+ if (!d->ref.deref())
+ delete d;
}
/*!
Sets the number of samples per pixel for a multisample framebuffer object
- to \a samples.
- A sample count of 0 represents a regular non-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 QGLFramebufferObjectFormat::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()
*/
@@ -195,18 +206,19 @@ int QGLFramebufferObjectFormat::samples() const
}
/*!
- Sets the attachments a framebuffer object should have to \a attachment.
+ Sets the attachment configuration of a framebuffer object to \a attachment.
\sa attachment()
*/
void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment)
{
+ detach();
d->attachment = attachment;
}
/*!
- Returns the status of the depth and stencil buffers attached to
- a framebuffer object.
+ Returns the configuration of the depth and stencil buffers attached to
+ a framebuffer object. The default is QGLFramebufferObject::NoAttachment.
\sa setAttachment()
*/
@@ -223,12 +235,14 @@ QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const
*/
void QGLFramebufferObjectFormat::setTextureTarget(GLenum target)
{
+ detach();
d->target = target;
}
/*!
Returns the texture target of the texture attached to a framebuffer object.
- Ignored for multisample framebuffer objects.
+ Ignored for multisample framebuffer objects. The default is
+ \c GL_TEXTURE_2D.
\sa setTextureTarget(), samples()
*/
@@ -238,53 +252,101 @@ GLenum QGLFramebufferObjectFormat::textureTarget() const
}
/*!
- Sets the internal format of a framebuffer object's texture or multisample
- framebuffer object's color buffer to \a internalFormat.
+ Sets the internal format of a framebuffer object's texture or
+ multisample framebuffer object's color buffer to
+ \a internalTextureFormat.
- \sa internalFormat()
+ \sa internalTextureFormat()
*/
-void QGLFramebufferObjectFormat::setInternalFormat(GLenum internalFormat)
+void QGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat)
{
- d->internal_format = internalFormat;
+ detach();
+ d->internal_format = internalTextureFormat;
}
/*!
Returns the internal format of a framebuffer object's texture or
- multisample framebuffer object's color buffer.
+ 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 setInternalFormat()
+ \sa setInternalTextureFormat()
*/
-GLenum QGLFramebufferObjectFormat::internalFormat() const
+GLenum QGLFramebufferObjectFormat::internalTextureFormat() const
{
return d->internal_format;
}
-class QGLFramebufferObjectPrivate
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+/*! \internal */
+void QGLFramebufferObjectFormat::setTextureTarget(QMacCompatGLenum target)
{
-public:
- QGLFramebufferObjectPrivate() : depth_stencil_buffer(0), valid(false), bound(false), ctx(0), previous_fbo(0) {}
- ~QGLFramebufferObjectPrivate() {}
-
- void init(const QSize& sz, QGLFramebufferObject::Attachment attachment,
- GLenum internal_format, GLenum texture_target, GLint samples = 0);
- bool checkFramebufferStatus() const;
- GLuint texture;
- GLuint fbo;
- GLuint depth_stencil_buffer;
- GLuint color_buffer;
- GLenum target;
- QSize size;
- QGLFramebufferObjectFormat format;
- int samples;
- uint valid : 1;
- uint bound : 1;
- QGLFramebufferObject::Attachment fbo_attachment;
- QGLContext *ctx; // for Windows extension ptrs
- GLuint previous_fbo;
-};
+ detach();
+ d->target = target;
+}
+
+/*! \internal */
+void QGLFramebufferObjectFormat::setInternalTextureFormat(QMacCompatGLenum internalTextureFormat)
+{
+ detach();
+ d->internal_format = internalTextureFormat;
+}
+#endif
+
+/*!
+ Returns true if all the options of this framebuffer object format
+ are the same as \a other; otherwise returns false.
+*/
+bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& 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 QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const
+{
+ return !(*this == other);
+}
+
+void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
+ QGLFramebufferObject::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 = QGLContext::currentContext()->format();
+ if (attachment == QGLFramebufferObject::CombinedDepthStencil) {
+ fboFormat.setDepth(true);
+ fboFormat.setStencil(true);
+ } else if (attachment == QGLFramebufferObject::Depth) {
+ fboFormat.setDepth(true);
+ }
+}
+
+QGLContext *QGLFBOGLPaintDevice::context() const
+{
+ QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context());
+ QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
+
+ if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext))
+ return currentContext;
+ else
+ return fboContext;
+}
bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
{
+ QGL_FUNCP_CONTEXT;
+ if (!ctx)
+ return false; // Context no longer exists.
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
switch(status) {
case GL_NO_ERROR:
@@ -327,10 +389,13 @@ bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
return false;
}
-void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::Attachment attachment,
+void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
+ QGLFramebufferObject::Attachment attachment,
GLenum texture_target, GLenum internal_format, GLint samples)
{
- ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ fbo_guard.setContext(ctx);
+
bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject);
if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
return;
@@ -339,9 +404,13 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
target = texture_target;
// texture dimensions
- while (glGetError() != GL_NO_ERROR) {} // reset error state
+ QT_RESET_GLERROR(); // reset error state
+ GLuint fbo = 0;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
+ fbo_guard.setId(fbo);
+
+ glDevice.setFBO(q, attachment);
QT_CHECK_GLERROR();
// init texture
@@ -366,9 +435,9 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
QT_CHECK_GLERROR();
valid = checkFramebufferStatus();
+ glBindTexture(target, 0);
color_buffer = 0;
- samples = 0;
} else {
GLint maxSamples;
glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
@@ -464,13 +533,14 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
else
glDeleteTextures(1, &texture);
glDeleteFramebuffers(1, &fbo);
+ fbo_guard.setId(0);
}
QT_CHECK_GLERROR();
format.setTextureTarget(target);
format.setSamples(int(samples));
format.setAttachment(fbo_attachment);
- format.setInternalFormat(internal_format);
+ format.setInternalTextureFormat(internal_format);
}
/*!
@@ -478,7 +548,7 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
\brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
\since 4.2
- \ingroup multimedia
+ \ingroup painting-3D
The QGLFramebufferObject class encapsulates an OpenGL framebuffer
object, defined by the \c{GL_EXT_framebuffer_object} extension. In
@@ -518,15 +588,21 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
framebuffer objects more portable.
\endlist
+ When using a QPainter to paint to a QGLFramebufferObject you should take
+ care that the QGLFramebufferObject is created with the CombinedDepthStencil
+ attachment for QPainter to be able to render correctly.
Note that you need to create a QGLFramebufferObject with more than one
sample per pixel for primitives to be antialiased when drawing using a
- QPainter, unless if the QPainter::HighQualityAntialiasing render hint is
- set. The QPainter::HighQualityAntialiasing render hint will enable
- antialiasing as long as the \c{GL_ARB_fragment_program} extension is
- present. To create a multisample framebuffer object you should use one of
+ QPainter. To create a multisample framebuffer object you should use one of
the constructors that take a QGLFramebufferObject parameter, and set the
QGLFramebufferObject::samples() property to a non-zero value.
+ 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 QGLContext::blitFramebuffer().
@@ -571,7 +647,8 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
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.
+ 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 QGLFramebufferObject, otherwise the initialization
@@ -580,17 +657,11 @@ void QGLFramebufferObjectPrivate::init(const QSize &sz, QGLFramebufferObject::At
\sa size(), texture(), attachment()
*/
-#ifndef QT_OPENGL_ES
-#define DEFAULT_FORMAT GL_RGBA8
-#else
-#define DEFAULT_FORMAT GL_RGBA
-#endif
-
QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, NoAttachment, target, DEFAULT_FORMAT);
+ d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -599,7 +670,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, QMacCompatGLenum t
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, NoAttachment, target, DEFAULT_FORMAT);
+ d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
}
#endif
@@ -614,7 +685,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
+ d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
}
/*! \overload
@@ -627,7 +698,8 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebuff
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, format.attachment(), format.textureTarget(), format.internalFormat(), format.samples());
+ d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
+ format.samples());
}
/*! \overload
@@ -640,7 +712,8 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFrame
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), format.attachment(), format.textureTarget(), format.internalFormat(), format.samples());
+ d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
+ format.internalTextureFormat(), format.samples());
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -649,7 +722,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLen
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
+ d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
}
#endif
@@ -661,7 +734,8 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLen
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.
+ 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()
*/
@@ -670,7 +744,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), attachment, target, internal_format);
+ d->init(this, QSize(width, height), attachment, target, internal_format);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -680,7 +754,7 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(QSize(width, height), attachment, target, internal_format);
+ d->init(this, QSize(width, height), attachment, target, internal_format);
}
#endif
@@ -692,7 +766,8 @@ QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment att
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.
+ 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()
*/
@@ -701,7 +776,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, attachment, target, internal_format);
+ d->init(this, size, attachment, target, internal_format);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -711,7 +786,7 @@ QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachm
: d_ptr(new QGLFramebufferObjectPrivate)
{
Q_D(QGLFramebufferObject);
- d->init(size, attachment, target, internal_format);
+ d->init(this, size, attachment, target, internal_format);
}
#endif
@@ -725,18 +800,19 @@ QGLFramebufferObject::~QGLFramebufferObject()
Q_D(QGLFramebufferObject);
QGL_FUNC_CONTEXT;
- if (isValid()
- && (d->ctx == QGLContext::currentContext()
- || qgl_share_reg()->checkSharing(d->ctx, QGLContext::currentContext())))
- {
- glDeleteTextures(1, &d->texture);
+ delete d->engine;
+
+ if (isValid() && ctx) {
+ QGLShareContextScope scope(ctx);
+ if (d->texture)
+ glDeleteTextures(1, &d->texture);
if (d->color_buffer)
glDeleteRenderbuffers(1, &d->color_buffer);
if (d->depth_stencil_buffer)
glDeleteRenderbuffers(1, &d->depth_stencil_buffer);
- glDeleteFramebuffers(1, &d->fbo);
+ GLuint fbo = d->fbo();
+ glDeleteFramebuffers(1, &fbo);
}
- delete d_ptr;
}
/*!
@@ -751,11 +827,16 @@ QGLFramebufferObject::~QGLFramebufferObject()
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 QGLContext that
+ the framebuffer was created within is destroyed and there are
+ no other shared contexts that can take over ownership of the
+ framebuffer.
*/
bool QGLFramebufferObject::isValid() const
{
Q_D(const QGLFramebufferObject);
- return d->valid;
+ return d->valid && d->fbo_guard.context();
}
/*!
@@ -765,13 +846,6 @@ bool QGLFramebufferObject::isValid() const
framebuffer to this framebuffer object.
Returns true upon success, false otherwise.
- Since 4.6: if another QGLFramebufferObject instance was already bound
- to the current context, then its handle() will be remembered and
- automatically restored when release() is called. This allows multiple
- framebuffer rendering targets to be stacked up. It is important that
- release() is called on the stacked framebuffer objects in the reverse
- order of the calls to bind().
-
\sa release()
*/
bool QGLFramebufferObject::bind()
@@ -780,16 +854,20 @@ bool QGLFramebufferObject::bind()
return false;
Q_D(QGLFramebufferObject);
QGL_FUNC_CONTEXT;
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo);
- d->bound = d->valid = d->checkFramebufferStatus();
- const QGLContext *context = QGLContext::currentContext();
- if (d->valid && context) {
- // Save the previous setting to automatically restore in release().
- if (context->d_ptr->current_fbo != d->fbo) {
- d->previous_fbo = context->d_ptr->current_fbo;
- context->d_ptr->current_fbo = d->fbo;
- }
+ if (!ctx)
+ return false; // Context no longer exists.
+ const QGLContext *current = QGLContext::currentContext();
+#ifdef QT_DEBUG
+ if (!current ||
+ QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
+ {
+ qWarning("QGLFramebufferObject::bind() called from incompatible context");
}
+#endif
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->fbo());
+ d->valid = d->checkFramebufferStatus();
+ if (d->valid && current)
+ current->d_ptr->current_fbo = d->fbo();
return d->valid;
}
@@ -800,28 +878,29 @@ bool QGLFramebufferObject::bind()
framebuffer.
Returns true upon success, false otherwise.
- Since 4.6: if another QGLFramebufferObject instance was already bound
- to the current context when bind() was called, then this function will
- automatically re-bind it to the current context.
-
\sa bind()
*/
bool QGLFramebufferObject::release()
{
if (!isValid())
return false;
- Q_D(QGLFramebufferObject);
QGL_FUNC_CONTEXT;
- d->bound = false;
-
- const QGLContext *context = QGLContext::currentContext();
- if (context) {
- // Restore the previous setting for stacked framebuffer objects.
- if (d->previous_fbo != context->d_ptr->current_fbo) {
- context->d_ptr->current_fbo = d->previous_fbo;
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, d->previous_fbo);
- }
- d->previous_fbo = 0;
+ if (!ctx)
+ return false; // Context no longer exists.
+
+ const QGLContext *current = QGLContext::currentContext();
+
+#ifdef QT_DEBUG
+ if (!current ||
+ QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
+ {
+ qWarning("QGLFramebufferObject::release() called from incompatible context");
+ }
+#endif
+
+ if (current) {
+ current->d_ptr->current_fbo = current->d_ptr->default_fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, current->d_ptr->default_fbo);
}
return true;
@@ -858,7 +937,7 @@ QSize QGLFramebufferObject::size() const
/*!
Returns the format of this framebuffer object.
*/
-const QGLFramebufferObjectFormat &QGLFramebufferObject::format() const
+QGLFramebufferObjectFormat QGLFramebufferObject::format() const
{
Q_D(const QGLFramebufferObject);
return d->format;
@@ -875,9 +954,22 @@ QImage QGLFramebufferObject::toImage() const
if (!d->valid)
return QImage();
- const_cast<QGLFramebufferObject *>(this)->bind();
- QImage image = qt_gl_read_framebuffer(d->size, d->ctx->format().alpha(), true);
- const_cast<QGLFramebufferObject *>(this)->release();
+ // qt_gl_read_framebuffer doesn't work on a multisample FBO
+ if (format().samples() != 0) {
+ QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
+
+ QRect rect(QPoint(0, 0), size());
+ blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
+
+ return temp.toImage();
+ }
+
+ bool wasBound = isBound();
+ if (!wasBound)
+ const_cast<QGLFramebufferObject *>(this)->bind();
+ QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
+ if (!wasBound)
+ const_cast<QGLFramebufferObject *>(this)->release();
return image;
}
@@ -893,16 +985,32 @@ Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
/*! \reimp */
QPaintEngine *QGLFramebufferObject::paintEngine() const
{
-#if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL)
- return qt_buffer_engine();
-#elif defined(QT_OPENGL_ES_2)
- return qt_buffer_2_engine();
-#else
Q_D(const QGLFramebufferObject);
- if (d->ctx->d_func()->internal_context || qt_gl_preferGL2Engine())
- return qt_buffer_2_engine();
- else
- return qt_buffer_engine();
+ if (d->engine)
+ return d->engine;
+
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+#if !defined (QT_OPENGL_ES_2)
+ if (qt_gl_preferGL2Engine()) {
+#endif
+ QPaintEngine *engine = qt_buffer_2_engine();
+ if (engine->isActive() && engine->paintDevice() != this) {
+ d->engine = new QGL2PaintEngineEx;
+ return d->engine;
+ }
+ return engine;
+#if !defined (QT_OPENGL_ES_2)
+ }
+#endif
+#endif
+
+#if !defined(QT_OPENGL_ES_2)
+ QPaintEngine *engine = qt_buffer_engine();
+ if (engine->isActive() && engine->paintDevice() != this) {
+ d->engine = new QOpenGLPaintEngine;
+ return d->engine;
+ }
+ return engine;
#endif
}
@@ -931,16 +1039,14 @@ bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
*/
void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
{
- Q_D(QGLFramebufferObject);
- d->ctx->drawTexture(target, textureId, textureTarget);
+ const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
/*! \internal */
void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
{
- Q_D(QGLFramebufferObject);
- d->ctx->drawTexture(target, textureId, textureTarget);
+ const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
}
#endif
@@ -956,16 +1062,14 @@ void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint te
*/
void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
{
- Q_D(QGLFramebufferObject);
- d->ctx->drawTexture(point, textureId, textureTarget);
+ const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
/*! \internal */
void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
{
- Q_D(QGLFramebufferObject);
- d->ctx->drawTexture(point, textureId, textureTarget);
+ const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
}
#endif
@@ -1031,7 +1135,7 @@ int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
GLuint QGLFramebufferObject::handle() const
{
Q_D(const QGLFramebufferObject);
- return d->fbo;
+ return d->fbo();
}
/*! \fn int QGLFramebufferObject::devType() const
@@ -1062,7 +1166,8 @@ QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const
bool QGLFramebufferObject::isBound() const
{
Q_D(const QGLFramebufferObject);
- return d->bound;
+ const QGLContext *current = QGLContext::currentContext();
+ return current ? current->d_ptr->current_fbo == d->fbo() : false;
}
/*!
@@ -1072,6 +1177,8 @@ bool QGLFramebufferObject::isBound() const
Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
is present on this system; otherwise returns false.
+
+ \sa blitFramebuffer()
*/
bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
{
@@ -1089,14 +1196,15 @@ bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
instead of a framebuffer object as source or target respectively.
The \a buffers parameter should be a mask consisting of any combination of
- COLOR_BUFFER_BIT, DEPTH_BUFFER_BIT, and STENCIL_BUFFER_BIT. Any buffer type
- that is not present both in the source and target buffers is ignored.
+ \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 DEPTH_BUFFER_BIT or
- STENCIL_BUFFER_BIT. The \a filter parameter should be set to GL_LINEAR or
- GL_NEAREST, and specifies whether linear or nearest interpolation should
- be used when scaling is performed.
+ 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
@@ -1107,6 +1215,8 @@ bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
This function will have no effect unless hasOpenGLFramebufferBlit() returns
true.
+
+ \sa hasOpenGLFramebufferBlit()
*/
void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
QGLFramebufferObject *source, const QRect &sourceRect,
diff --git a/src/opengl/qglframebufferobject.h b/src/opengl/qglframebufferobject.h
index 6a82aeeb6..6cf557127 100644
--- a/src/opengl/qglframebufferobject.h
+++ b/src/opengl/qglframebufferobject.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -93,7 +93,7 @@ public:
virtual ~QGLFramebufferObject();
- const QGLFramebufferObjectFormat &format() const;
+ QGLFramebufferObjectFormat format() const;
bool isValid() const;
bool isBound() const;
@@ -129,26 +129,16 @@ protected:
private:
Q_DISABLE_COPY(QGLFramebufferObject)
- QGLFramebufferObjectPrivate *d_ptr;
- friend class QGLDrawable;
+ QScopedPointer<QGLFramebufferObjectPrivate> d_ptr;
+ friend class QGLPaintDevice;
+ friend class QGLFBOGLPaintDevice;
};
class QGLFramebufferObjectFormatPrivate;
class Q_OPENGL_EXPORT QGLFramebufferObjectFormat
{
public:
-#if !defined(QT_OPENGL_ES) || defined(Q_QDOC)
- QGLFramebufferObjectFormat(int samples = 0,
- QGLFramebufferObject::Attachment attachment = QGLFramebufferObject::NoAttachment,
- GLenum target = GL_TEXTURE_2D,
- GLenum internalFormat = GL_RGBA8);
-#else
- QGLFramebufferObjectFormat(int samples = 0,
- QGLFramebufferObject::Attachment attachment = QGLFramebufferObject::NoAttachment,
- GLenum target = GL_TEXTURE_2D,
- GLenum internalFormat = GL_RGBA);
-#endif
-
+ QGLFramebufferObjectFormat();
QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other);
QGLFramebufferObjectFormat &operator=(const QGLFramebufferObjectFormat &other);
~QGLFramebufferObjectFormat();
@@ -162,11 +152,21 @@ public:
void setTextureTarget(GLenum target);
GLenum textureTarget() const;
- void setInternalFormat(GLenum internalFormat);
- GLenum internalFormat() const;
+ void setInternalTextureFormat(GLenum internalTextureFormat);
+ GLenum internalTextureFormat() const;
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+ void setTextureTarget(QMacCompatGLenum target);
+ void setInternalTextureFormat(QMacCompatGLenum internalTextureFormat);
+#endif
+
+ bool operator==(const QGLFramebufferObjectFormat& other) const;
+ bool operator!=(const QGLFramebufferObjectFormat& other) const;
private:
QGLFramebufferObjectFormatPrivate *d;
+
+ void detach();
};
QT_END_NAMESPACE
diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h
new file mode 100644
index 000000000..800cb683b
--- /dev/null
+++ b/src/opengl/qglframebufferobject_p.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLFRAMEBUFFEROBJECT_P_H
+#define QGLFRAMEBUFFEROBJECT_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 <qglframebufferobject.h>
+#include <private/qglpaintdevice_p.h>
+#include <private/qgl_p.h>
+
+QT_END_INCLUDE_NAMESPACE
+
+#ifndef QT_OPENGL_ES
+#define DEFAULT_FORMAT GL_RGBA8
+#else
+#define DEFAULT_FORMAT GL_RGBA
+#endif
+
+class QGLFramebufferObjectFormatPrivate
+{
+public:
+ QGLFramebufferObjectFormatPrivate()
+ : ref(1),
+ samples(0),
+ attachment(QGLFramebufferObject::NoAttachment),
+ target(GL_TEXTURE_2D),
+ internal_format(DEFAULT_FORMAT)
+ {
+ }
+ QGLFramebufferObjectFormatPrivate
+ (const QGLFramebufferObjectFormatPrivate *other)
+ : ref(1),
+ samples(other->samples),
+ attachment(other->attachment),
+ target(other->target),
+ internal_format(other->internal_format)
+ {
+ }
+ bool equals(const QGLFramebufferObjectFormatPrivate *other)
+ {
+ return samples == other->samples &&
+ attachment == other->attachment &&
+ target == other->target &&
+ internal_format == other->internal_format;
+ }
+
+ QAtomicInt ref;
+ int samples;
+ QGLFramebufferObject::Attachment attachment;
+ GLenum target;
+ GLenum internal_format;
+};
+
+class QGLFBOGLPaintDevice : public QGLPaintDevice
+{
+public:
+ virtual QPaintEngine* paintEngine() const {return fbo->paintEngine();}
+ virtual QSize size() const {return fbo->size();}
+ virtual QGLContext* context() const;
+ virtual QGLFormat format() const {return fboFormat;}
+
+ void setFBO(QGLFramebufferObject* f,
+ QGLFramebufferObject::Attachment attachment);
+
+private:
+ bool wasBound;
+ QGLFramebufferObject* fbo;
+ QGLFormat fboFormat;
+};
+
+class QGLFramebufferObjectPrivate
+{
+public:
+ QGLFramebufferObjectPrivate() : fbo_guard(0), texture(0), depth_stencil_buffer(0)
+ , color_buffer(0), valid(false), engine(0) {}
+ ~QGLFramebufferObjectPrivate() {}
+
+ void init(QGLFramebufferObject *q, const QSize& sz,
+ QGLFramebufferObject::Attachment attachment,
+ GLenum internal_format, GLenum texture_target, GLint samples = 0);
+ bool checkFramebufferStatus() const;
+ QGLSharedResourceGuard fbo_guard;
+ GLuint texture;
+ GLuint depth_stencil_buffer;
+ GLuint color_buffer;
+ GLenum target;
+ QSize size;
+ QGLFramebufferObjectFormat format;
+ uint valid : 1;
+ QGLFramebufferObject::Attachment fbo_attachment;
+ mutable QPaintEngine *engine;
+ QGLFBOGLPaintDevice glDevice;
+
+ inline GLuint fbo() const { return fbo_guard.id(); }
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QGLFRAMEBUFFEROBJECT_P_H
diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp
new file mode 100644
index 000000000..bcd90a5fb
--- /dev/null
+++ b/src/opengl/qglpaintdevice.cpp
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qglpaintdevice_p.h>
+#include <private/qgl_p.h>
+#include <private/qglpixelbuffer_p.h>
+#include <private/qglframebufferobject_p.h>
+#include <private/qwindowsurface_gl_p.h>
+#ifdef Q_WS_X11
+#include <private/qpixmapdata_x11gl_p.h>
+#endif
+
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+#include <private/qpixmapdata_gl_p.h>
+#endif
+
+#if defined(QT_OPENGL_ES_1_CL)
+#include "qgl_cl_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QGLPaintDevice::QGLPaintDevice()
+ : m_thisFBO(0)
+{
+}
+
+QGLPaintDevice::~QGLPaintDevice()
+{
+}
+
+
+void QGLPaintDevice::beginPaint()
+{
+ // Make sure our context is the current one:
+ QGLContext *ctx = context();
+ if (ctx != QGLContext::currentContext())
+ ctx->makeCurrent();
+
+ // 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_ptr->current_fbo = m_thisFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO);
+ }
+
+ // Set the default fbo for the context to m_thisFBO so that
+ // if some raw GL code between beginNativePainting() and
+ // endNativePainting() calls QGLFramebufferObject::release(),
+ // painting will revert to the window surface's fbo.
+ ctx->d_ptr->default_fbo = m_thisFBO;
+}
+
+void QGLPaintDevice::ensureActiveTarget()
+{
+ QGLContext* ctx = context();
+ if (ctx != QGLContext::currentContext())
+ ctx->makeCurrent();
+
+ if (ctx->d_ptr->current_fbo != m_thisFBO) {
+ ctx->d_ptr->current_fbo = m_thisFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO);
+ }
+
+ ctx->d_ptr->default_fbo = m_thisFBO;
+}
+
+void QGLPaintDevice::endPaint()
+{
+ // Make sure the FBO bound at beginPaint is re-bound again here:
+ QGLContext *ctx = context();
+ if (m_previousFBO != ctx->d_func()->current_fbo) {
+ ctx->d_ptr->current_fbo = m_previousFBO;
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_previousFBO);
+ }
+
+ ctx->d_ptr->default_fbo = 0;
+}
+
+QGLFormat QGLPaintDevice::format() const
+{
+ return context()->format();
+}
+
+
+
+
+////////////////// QGLWidgetGLPaintDevice //////////////////
+
+QGLWidgetGLPaintDevice::QGLWidgetGLPaintDevice()
+{
+}
+
+QPaintEngine* QGLWidgetGLPaintDevice::paintEngine() const
+{
+ return glWidget->paintEngine();
+}
+
+void QGLWidgetGLPaintDevice::setWidget(QGLWidget* w)
+{
+ glWidget = w;
+}
+
+void QGLWidgetGLPaintDevice::beginPaint()
+{
+ QGLPaintDevice::beginPaint();
+ if (!glWidget->d_func()->disable_clear_on_painter_begin && glWidget->autoFillBackground()) {
+ if (glWidget->testAttribute(Qt::WA_TranslucentBackground))
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ else {
+ const QColor &c = glWidget->palette().brush(glWidget->backgroundRole()).color();
+ float alpha = c.alphaF();
+ glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
+ }
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+}
+
+void QGLWidgetGLPaintDevice::endPaint()
+{
+ if (glWidget->autoBufferSwap())
+ glWidget->swapBuffers();
+ QGLPaintDevice::endPaint();
+}
+
+
+QSize QGLWidgetGLPaintDevice::size() const
+{
+ return glWidget->size();
+}
+
+QGLContext* QGLWidgetGLPaintDevice::context() const
+{
+ return const_cast<QGLContext*>(glWidget->context());
+}
+
+// returns the QGLPaintDevice for the given QPaintDevice
+QGLPaintDevice* QGLPaintDevice::getDevice(QPaintDevice* pd)
+{
+ QGLPaintDevice* glpd = 0;
+
+ switch(pd->devType()) {
+ case QInternal::Widget:
+ // Should not be called on a non-gl widget:
+ Q_ASSERT(qobject_cast<QGLWidget*>(static_cast<QWidget*>(pd)));
+ glpd = &(static_cast<QGLWidget*>(pd)->d_func()->glDevice);
+ break;
+ case QInternal::Pbuffer:
+ glpd = &(static_cast<QGLPixelBuffer*>(pd)->d_func()->glDevice);
+ break;
+ case QInternal::FramebufferObject:
+ glpd = &(static_cast<QGLFramebufferObject*>(pd)->d_func()->glDevice);
+ break;
+ case QInternal::Pixmap: {
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+ QPixmapData* pmd = static_cast<QPixmap*>(pd)->pixmapData();
+ if (pmd->classId() == QPixmapData::OpenGLClass)
+ glpd = static_cast<QGLPixmapData*>(pmd)->glDevice();
+#ifdef Q_WS_X11
+ else if (pmd->classId() == QPixmapData::X11Class)
+ glpd = static_cast<QX11GLPixmapData*>(pmd);
+#endif
+ else
+ qWarning("Pixmap type not supported for GL rendering");
+#else
+ qWarning("Pixmap render targets not supported on OpenGL ES 1.x");
+#endif
+ break;
+ }
+ default:
+ qWarning("QGLPaintDevice::getDevice() - Unknown device type %d", pd->devType());
+ break;
+ }
+
+ return glpd;
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qglpaintdevice_p.h b/src/opengl/qglpaintdevice_p.h
new file mode 100644
index 000000000..63ba5da45
--- /dev/null
+++ b/src/opengl/qglpaintdevice_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGLPAINTDEVICE_P_H
+#define QGLPAINTDEVICE_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 QtOpenGL module. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <qpaintdevice.h>
+#include <qgl.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class Q_OPENGL_EXPORT QGLPaintDevice : public QPaintDevice
+{
+public:
+ QGLPaintDevice();
+ virtual ~QGLPaintDevice();
+
+ int devType() const {return QInternal::OpenGL;}
+
+ virtual void beginPaint();
+ virtual void ensureActiveTarget();
+ virtual void endPaint();
+
+ virtual QGLContext* context() const = 0;
+ virtual QGLFormat format() const;
+ virtual QSize size() const = 0;
+
+ // returns the QGLPaintDevice for the given QPaintDevice
+ static QGLPaintDevice* getDevice(QPaintDevice*);
+
+protected:
+ GLuint m_previousFBO;
+ GLuint m_thisFBO;
+};
+
+
+// Wraps a QGLWidget
+class QGLWidget;
+class QGLWidgetGLPaintDevice : public QGLPaintDevice
+{
+public:
+ QGLWidgetGLPaintDevice();
+
+ virtual QPaintEngine* paintEngine() const;
+
+ // QGLWidgets need to do swapBufers in endPaint:
+ virtual void beginPaint();
+ virtual void endPaint();
+ virtual QSize size() const;
+ virtual QGLContext* context() const;
+
+ void setWidget(QGLWidget*);
+
+private:
+ friend class QGLWidget;
+ QGLWidget *glWidget;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGLPAINTDEVICE_P_H
diff --git a/src/opengl/qglpaintdevice_qws.cpp b/src/opengl/qglpaintdevice_qws.cpp
deleted file mode 100644
index 62752d049..000000000
--- a/src/opengl/qglpaintdevice_qws.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtOpenGL module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain
-** additional rights. These rights are described in the Nokia Qt LGPL
-** Exception version 1.0, 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.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <private/qglpaintdevice_qws_p.h>
-#include <private/qgl_p.h>
-#include <private/qpaintengine_opengl_p.h>
-#include <private/qglwindowsurface_qws_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QWSGLPaintDevicePrivate
-{
-public:
- QWidget *widget;
-};
-
-class QMetricAccessor : public QWidget {
-public:
- int metric(PaintDeviceMetric m) {
- return QWidget::metric(m);
- }
-};
-
-QWSGLPaintDevice::QWSGLPaintDevice(QWidget *widget) :
- d_ptr(new QWSGLPaintDevicePrivate)
-{
- Q_D(QWSGLPaintDevice);
- d->widget = widget;
-}
-
-QWSGLPaintDevice::~QWSGLPaintDevice()
-{
- Q_D(QWSGLPaintDevice);
- delete d;
-}
-
-QPaintEngine* QWSGLPaintDevice::paintEngine() const
-{
-#if !defined(QT_OPENGL_ES_2)
- return qt_qgl_paint_engine();
-#else
- return 0; // XXX
-#endif
-}
-
-int QWSGLPaintDevice::metric(PaintDeviceMetric m) const
-{
- Q_D(const QWSGLPaintDevice);
- Q_ASSERT(d->widget);
-
- return ((QMetricAccessor *) d->widget)->metric(m);
-}
-
-QWSGLWindowSurface* QWSGLPaintDevice::windowSurface() const
-{
- Q_D(const QWSGLPaintDevice);
- return static_cast<QWSGLWindowSurface*>(d->widget->windowSurface());
-}
-
-QT_END_NAMESPACE
diff --git a/src/opengl/qglpaintdevice_qws_p.h b/src/opengl/qglpaintdevice_qws_p.h
deleted file mode 100644
index eba7d1ead..000000000
--- a/src/opengl/qglpaintdevice_qws_p.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtOpenGL module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain
-** additional rights. These rights are described in the Nokia Qt LGPL
-** Exception version 1.0, 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.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QWSGLPAINTDEVICE_GL_P_H
-#define QWSGLPAINTDEVICE_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 QGLWindowSurface class. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QPaintDevice>
-
-QT_BEGIN_NAMESPACE
-
-class QWidget;
-class QWSGLWindowSurface;
-class QWSGLPaintDevicePrivate;
-
-class Q_OPENGL_EXPORT QWSGLPaintDevice : public QPaintDevice
-{
- Q_DECLARE_PRIVATE(QWSGLPaintDevice)
-public:
- QWSGLPaintDevice(QWidget *widget);
- ~QWSGLPaintDevice();
-
- QPaintEngine *paintEngine() const;
-
- int metric(PaintDeviceMetric m) const;
-
- QWSGLWindowSurface *windowSurface() const;
-
-private:
- friend class QWSGLWindowSurface;
- QWSGLPaintDevicePrivate *d_ptr;
-};
-
-
-QT_END_NAMESPACE
-
-#endif // QWSGLPAINTDEVICE_GL_P_H
diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp
index 884bb360d..7c97ebb73 100644
--- a/src/opengl/qglpixelbuffer.cpp
+++ b/src/opengl/qglpixelbuffer.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -44,7 +44,7 @@
\brief The QGLPixelBuffer class encapsulates an OpenGL pbuffer.
\since 4.1
- \ingroup multimedia
+ \ingroup painting-3D
Rendering into a pbuffer is normally done using full hardware
acceleration. This can be significantly faster than rendering
@@ -100,6 +100,22 @@ void qgl_cleanup_glyph_cache(QGLContext *) {}
extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
+
+QGLContext* QGLPBufferGLPaintDevice::context() const
+{
+ return pbuf->d_func()->qctx;
+}
+
+void QGLPBufferGLPaintDevice::endPaint() {
+ glFlush();
+ QGLPaintDevice::endPaint();
+}
+
+void QGLPBufferGLPaintDevice::setPBuffer(QGLPixelBuffer* pb)
+{
+ pbuf = pb;
+}
+
void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &format, QGLWidget *shareWidget)
{
Q_Q(QGLPixelBuffer);
@@ -110,9 +126,12 @@ void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &form
invalid = false;
qctx = new QGLContext(format);
qctx->d_func()->sharing = (shareWidget != 0);
- if (shareWidget != 0 && shareWidget->d_func()->glcx)
+ if (shareWidget != 0 && shareWidget->d_func()->glcx) {
qgl_share_reg()->addShare(qctx, shareWidget->d_func()->glcx);
+ shareWidget->d_func()->glcx->d_func()->sharing = true;
+ }
+ glDevice.setPBuffer(q);
qctx->d_func()->paintDevice = q;
qctx->d_func()->valid = true;
#if defined(Q_WS_WIN) && !defined(QT_OPENGL_ES)
@@ -127,6 +146,7 @@ void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &form
qctx->d_func()->vi = 0;
#elif defined(QT_OPENGL_ES)
qctx->d_func()->eglContext = ctx;
+ qctx->d_func()->eglSurface = pbuf;
#endif
}
}
@@ -191,7 +211,6 @@ QGLPixelBuffer::~QGLPixelBuffer()
delete d->qctx;
if (current && current != d->qctx)
current->makeCurrent();
- delete d_ptr;
}
/*! \fn bool QGLPixelBuffer::makeCurrent()
@@ -384,7 +403,7 @@ QPaintEngine *QGLPixelBuffer::paintEngine() const
#elif defined(QT_OPENGL_ES_2)
return qt_buffer_2_engine();
#else
- if (d_ptr->qctx->d_func()->internal_context || qt_gl_preferGL2Engine())
+ if (qt_gl_preferGL2Engine())
return qt_buffer_2_engine();
else
return qt_buffer_engine();
diff --git a/src/opengl/qglpixelbuffer.h b/src/opengl/qglpixelbuffer.h
index 762c93388..94ecd4613 100644
--- a/src/opengl/qglpixelbuffer.h
+++ b/src/opengl/qglpixelbuffer.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -107,9 +107,11 @@ protected:
private:
Q_DISABLE_COPY(QGLPixelBuffer)
- QGLPixelBufferPrivate *d_ptr;
+ QScopedPointer<QGLPixelBufferPrivate> d_ptr;
friend class QGLDrawable;
friend class QGLWindowSurface;
+ friend class QGLPaintDevice;
+ friend class QGLPBufferGLPaintDevice;
};
QT_END_NAMESPACE
diff --git a/src/opengl/qglpixelbuffer_egl.cpp b/src/opengl/qglpixelbuffer_egl.cpp
index 2932c77d8..de08655b3 100644
--- a/src/opengl/qglpixelbuffer_egl.cpp
+++ b/src/opengl/qglpixelbuffer_egl.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -72,37 +72,53 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge
return false;
}
+ // Find the shared context.
+ QEglContext *shareContext = 0;
+ if (shareWidget && shareWidget->d_func()->glcx)
+ shareContext = shareWidget->d_func()->glcx->d_func()->eglContext;
+
// Choose an appropriate configuration. We use the best format
// we can find, even if it is greater than the requested format.
// We try for a pbuffer that is capable of texture rendering if possible.
- QEglProperties configProps;
- qt_egl_set_format(configProps, QInternal::Pbuffer, f);
- configProps.setRenderableType(ctx->api());
- bool ok = false;
+ textureFormat = EGL_NONE;
+ if (shareContext) {
+ // Use the same configuration as the widget we are sharing with.
+ ctx->setConfig(shareContext->config());
+#if QGL_RENDER_TEXTURE
+ EGLint value = EGL_FALSE;
+ if (ctx->configAttrib(EGL_BIND_TO_TEXTURE_RGBA, &value) && value)
+ textureFormat = EGL_TEXTURE_RGBA;
+ else if (ctx->configAttrib(EGL_BIND_TO_TEXTURE_RGB, &value) && value)
+ textureFormat = EGL_TEXTURE_RGB;
+#endif
+ } else {
+ QEglProperties configProps;
+ qt_egl_set_format(configProps, QInternal::Pbuffer, f);
+ configProps.setRenderableType(ctx->api());
+ bool ok = false;
#if QGL_RENDER_TEXTURE
- textureFormat = EGL_TEXTURE_RGBA;
- configProps.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
- ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat);
- if (!ok) {
- // Try again with RGB texture rendering.
- textureFormat = EGL_TEXTURE_RGB;
- configProps.removeValue(EGL_BIND_TO_TEXTURE_RGBA);
- configProps.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
+ textureFormat = EGL_TEXTURE_RGBA;
+ configProps.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE);
ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat);
if (!ok) {
- // One last try for a pbuffer with no texture rendering.
- configProps.removeValue(EGL_BIND_TO_TEXTURE_RGB);
- textureFormat = EGL_NONE;
+ // Try again with RGB texture rendering.
+ textureFormat = EGL_TEXTURE_RGB;
+ configProps.removeValue(EGL_BIND_TO_TEXTURE_RGBA);
+ configProps.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE);
+ ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat);
+ if (!ok) {
+ // One last try for a pbuffer with no texture rendering.
+ configProps.removeValue(EGL_BIND_TO_TEXTURE_RGB);
+ textureFormat = EGL_NONE;
+ }
}
- }
-#else
- textureFormat = EGL_NONE;
#endif
- if (!ok) {
- if (!ctx->chooseConfig(configProps, QEgl::BestPixelFormat)) {
- delete ctx;
- ctx = 0;
- return false;
+ if (!ok) {
+ if (!ctx->chooseConfig(configProps, QEgl::BestPixelFormat)) {
+ delete ctx;
+ ctx = 0;
+ return false;
+ }
}
}
@@ -135,12 +151,8 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge
qWarning() << "QGLPixelBufferPrivate::init(): Unable to create EGL pbuffer surface:" << QEglContext::errorString(eglGetError());
return false;
}
- ctx->setSurface(pbuf);
// Create a new context for the configuration.
- QEglContext *shareContext = 0;
- if (shareWidget && shareWidget->d_func()->glcx)
- shareContext = shareWidget->d_func()->glcx->d_func()->eglContext;
if (!ctx->createContext(shareContext)) {
delete ctx;
ctx = 0;
@@ -152,7 +164,7 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge
bool QGLPixelBufferPrivate::cleanup()
{
- eglDestroySurface(QEglContext::defaultDisplay(0), pbuf);
+ // No need to destroy "pbuf" here - it is done in QGLContext::reset().
return true;
}
@@ -163,7 +175,7 @@ bool QGLPixelBuffer::bindToDynamicTexture(GLuint texture_id)
if (d->invalid || d->textureFormat == EGL_NONE || !d->ctx)
return false;
glBindTexture(GL_TEXTURE_2D, texture_id);
- return eglBindTexImage(d->ctx->display(), d->ctx->surface(), EGL_BACK_BUFFER);
+ return eglBindTexImage(d->ctx->display(), d->pbuf, EGL_BACK_BUFFER);
#else
Q_UNUSED(texture_id);
return false;
@@ -176,7 +188,7 @@ void QGLPixelBuffer::releaseFromDynamicTexture()
Q_D(QGLPixelBuffer);
if (d->invalid || d->textureFormat == EGL_NONE || !d->ctx)
return;
- eglReleaseTexImage(d->ctx->display(), d->ctx->surface(), EGL_BACK_BUFFER);
+ eglReleaseTexImage(d->ctx->display(), d->pbuf, EGL_BACK_BUFFER);
#endif
}
@@ -203,13 +215,20 @@ GLuint QGLPixelBuffer::generateDynamicTexture() const
bool QGLPixelBuffer::hasOpenGLPbuffers()
{
// See if we have at least 1 configuration that matches the default format.
- QEglContext ctx;
- if (!ctx.openDisplay(0))
+ EGLDisplay dpy = QEglContext::defaultDisplay(0);
+ if (dpy == EGL_NO_DISPLAY)
return false;
QEglProperties configProps;
qt_egl_set_format(configProps, QInternal::Pbuffer, QGLFormat::defaultFormat());
configProps.setRenderableType(QEgl::OpenGL);
- return ctx.chooseConfig(configProps);
+ do {
+ EGLConfig cfg = 0;
+ EGLint matching = 0;
+ if (eglChooseConfig(dpy, configProps.properties(),
+ &cfg, 1, &matching) && matching > 0)
+ return true;
+ } while (configProps.reduceConfiguration());
+ return false;
}
QT_END_NAMESPACE
diff --git a/src/opengl/qglpixelbuffer_mac.mm b/src/opengl/qglpixelbuffer_mac.mm
index 9a8ea6355..6b9344bbe 100644
--- a/src/opengl/qglpixelbuffer_mac.mm
+++ b/src/opengl/qglpixelbuffer_mac.mm
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/qglpixelbuffer_p.h b/src/opengl/qglpixelbuffer_p.h
index 224188a67..7fde8029b 100644
--- a/src/opengl/qglpixelbuffer_p.h
+++ b/src/opengl/qglpixelbuffer_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE
QT_BEGIN_INCLUDE_NAMESPACE
#include "QtOpenGL/qglpixelbuffer.h"
#include <private/qgl_p.h>
+#include <private/qglpaintdevice_p.h>
#if defined(Q_WS_X11) && !defined(QT_OPENGL_ES)
#include <GL/glx.h>
@@ -135,6 +136,19 @@ QT_END_INCLUDE_NAMESPACE
class QEglContext;
+
+class QGLPBufferGLPaintDevice : public QGLPaintDevice
+{
+public:
+ virtual QPaintEngine* paintEngine() const {return pbuf->paintEngine();}
+ virtual QSize size() const {return pbuf->size();}
+ virtual QGLContext* context() const;
+ virtual void endPaint();
+ void setPBuffer(QGLPixelBuffer* pb);
+private:
+ QGLPixelBuffer* pbuf;
+};
+
class QGLPixelBufferPrivate {
Q_DECLARE_PUBLIC(QGLPixelBuffer)
public:
@@ -154,6 +168,7 @@ public:
QGLPixelBuffer *q_ptr;
bool invalid;
QGLContext *qctx;
+ QGLPBufferGLPaintDevice glDevice;
QGLFormat format;
QGLFormat req_format;
diff --git a/src/opengl/qglpixelbuffer_win.cpp b/src/opengl/qglpixelbuffer_win.cpp
index 7073eefd5..71b37ca54 100644
--- a/src/opengl/qglpixelbuffer_win.cpp
+++ b/src/opengl/qglpixelbuffer_win.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/qglpixelbuffer_x11.cpp b/src/opengl/qglpixelbuffer_x11.cpp
index 9e15dcba4..697113336 100644
--- a/src/opengl/qglpixelbuffer_x11.cpp
+++ b/src/opengl/qglpixelbuffer_x11.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -93,6 +93,8 @@ static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0;
#define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib
#define glXMakeContextCurrent qt_glXMakeContextCurrent
+extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp
+
static bool qt_resolve_pbuffer_extensions()
{
static int resolved = false;
@@ -101,31 +103,12 @@ static bool qt_resolve_pbuffer_extensions()
else if (resolved)
return false;
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
- void *handle = dlopen(NULL, RTLD_LAZY);
- if (handle) {
- qt_glXChooseFBConfig = (_glXChooseFBConfig) dlsym(handle, "glXChooseFBConfig");
- qt_glXCreateNewContext = (_glXCreateNewContext) dlsym(handle, "glXCreateNewContext");
- qt_glXCreatePbuffer = (_glXCreatePbuffer) dlsym(handle, "glXCreatePbuffer");
- qt_glXDestroyPbuffer = (_glXDestroyPbuffer) dlsym(handle, "glXDestroyPbuffer");
- qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) dlsym(handle, "glXGetFBConfigAttrib");
- qt_glXMakeContextCurrent = (_glXMakeContextCurrent) dlsym(handle, "glXMakeContextCurrent");
- dlclose(handle);
- }
- if (!qt_glXChooseFBConfig)
-#endif
- {
-#if !defined(QT_NO_LIBRARY)
- extern const QString qt_gl_library_name();
- QLibrary gl(qt_gl_library_name());
- qt_glXChooseFBConfig = (_glXChooseFBConfig) gl.resolve("glXChooseFBConfig");
- qt_glXCreateNewContext = (_glXCreateNewContext) gl.resolve("glXCreateNewContext");
- qt_glXCreatePbuffer = (_glXCreatePbuffer) gl.resolve("glXCreatePbuffer");
- qt_glXDestroyPbuffer = (_glXDestroyPbuffer) gl.resolve("glXDestroyPbuffer");
- qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) gl.resolve("glXGetFBConfigAttrib");
- qt_glXMakeContextCurrent = (_glXMakeContextCurrent) gl.resolve("glXMakeContextCurrent");
-#endif
- }
+ qt_glXChooseFBConfig = (_glXChooseFBConfig) qglx_getProcAddress("glXChooseFBConfig");
+ qt_glXCreateNewContext = (_glXCreateNewContext) qglx_getProcAddress("glXCreateNewContext");
+ qt_glXCreatePbuffer = (_glXCreatePbuffer) qglx_getProcAddress("glXCreatePbuffer");
+ qt_glXDestroyPbuffer = (_glXDestroyPbuffer) qglx_getProcAddress("glXDestroyPbuffer");
+ qt_glXGetFBConfigAttrib = (_glXGetFBConfigAttrib) qglx_getProcAddress("glXGetFBConfigAttrib");
+ qt_glXMakeContextCurrent = (_glXMakeContextCurrent) qglx_getProcAddress("glXMakeContextCurrent");
resolved = qt_glXMakeContextCurrent ? true : false;
return resolved;
diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp
index f8e422621..c47863055 100644
--- a/src/opengl/qglpixmapfilter.cpp
+++ b/src/opengl/qglpixmapfilter.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,43 +21,48 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
#include "private/qpixmapfilter_p.h"
+#include "private/qpixmapdata_gl_p.h"
+#include "private/qpaintengineex_opengl2_p.h"
+#include "private/qglengineshadermanager_p.h"
+#include "private/qpixmapdata_p.h"
+#include "private/qimagepixmapcleanuphooks_p.h"
#include "qglpixmapfilter_p.h"
#include "qgraphicssystem_gl_p.h"
#include "qpaintengine_opengl_p.h"
+#include "qcache.h"
-#include "qglpixelbuffer.h"
+#include "qglframebufferobject.h"
#include "qglshaderprogram.h"
#include "qgl_p.h"
#include "private/qapplication_p.h"
-
+#include "private/qmath_p.h"
+#include "qmath.h"
QT_BEGIN_NAMESPACE
-
void QGLPixmapFilterBase::bindTexture(const QPixmap &src) const
{
- const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, true, false);
+ const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, QGLContext::BindOptions(QGLContext::DefaultBindOption | QGLContext::MemoryManagedBindOption));
}
void QGLPixmapFilterBase::drawImpl(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF& source) const
@@ -64,221 +70,971 @@ void QGLPixmapFilterBase::drawImpl(QPainter *painter, const QPointF &pos, const
processGL(painter, pos, src, source);
}
-class QGLPixmapColorizeFilter: public QGLPixmapFilter<QPixmapColorizeFilter>
+class QGLPixmapColorizeFilter: public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapColorizeFilter>
{
public:
QGLPixmapColorizeFilter();
+ void setUniforms(QGLShaderProgram *program);
+
protected:
bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &pixmap, const QRectF &srcRect) const;
-
-private:
- mutable QGLShaderProgram m_program;
- int m_colorUniform;
};
-class QGLPixmapConvolutionFilter: public QGLPixmapFilter<QPixmapConvolutionFilter>
+class QGLPixmapConvolutionFilter: public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapConvolutionFilter>
{
public:
QGLPixmapConvolutionFilter();
~QGLPixmapConvolutionFilter();
+ void setUniforms(QGLShaderProgram *program);
+
protected:
bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const;
private:
QByteArray generateConvolutionShader() const;
- mutable QGLShaderProgram *m_program;
- mutable int m_scaleUniform;
- mutable int m_matrixUniform;
-
- mutable int m_kernelWidth;
- mutable int m_kernelHeight;
+ mutable QSize m_srcSize;
+ mutable int m_prevKernelSize;
};
-extern QGLWidget *qt_gl_share_widget();
-
-QPixmapFilter *QGLContextPrivate::createPixmapFilter(int type) const
+class QGLPixmapBlurFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapBlurFilter>
{
- switch (type) {
- case QPixmapFilter::ColorizeFilter:
- return new QGLPixmapColorizeFilter;
+public:
+ QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHints hints);
+ void setUniforms(QGLShaderProgram *program);
- case QPixmapFilter::ConvolutionFilter:
- return new QGLPixmapConvolutionFilter;
+ static QByteArray generateGaussianShader(int radius, bool singlePass = false, bool dropShadow = false);
- default:
- return 0;
- break;
- }
- return 0;
-}
+protected:
+ bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const;
+
+private:
-extern void qt_add_rect_to_array(const QRectF &r, q_vertexType *array);
-extern void qt_add_texcoords_to_array(qreal x1, qreal y1, qreal x2, qreal y2, q_vertexType *array);
+ mutable QSize m_textureSize;
+ mutable bool m_horizontalBlur;
+ mutable bool m_singlePass;
+ mutable bool m_animatedBlur;
-static void qgl_drawTexture(const QRectF &rect, int tx_width, int tx_height, const QRectF & src)
+ mutable qreal m_t;
+ mutable QSize m_targetSize;
+
+ mutable bool m_haveCached;
+ mutable int m_cachedRadius;
+ mutable QGraphicsBlurEffect::BlurHints m_hints;
+};
+
+class QGLPixmapDropShadowFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapDropShadowFilter>
{
-#ifndef QT_OPENGL_ES_2 // XXX: needs to be ported
-#ifndef QT_OPENGL_ES
- glPushAttrib(GL_CURRENT_BIT);
-#endif
- qreal x1, x2, y1, y2;
+public:
+ QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHints hints);
+
+ void setUniforms(QGLShaderProgram *program);
+
+protected:
+ bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const;
+
+private:
+ mutable QSize m_textureSize;
+ mutable bool m_horizontalBlur;
+ mutable bool m_singlePass;
+
+ mutable bool m_haveCached;
+ mutable int m_cachedRadius;
+ mutable QGraphicsBlurEffect::BlurHints m_hints;
+};
- x1 = src.x() / tx_width;
- x2 = x1 + src.width() / tx_width;
- y1 = 1.0 - ((src.y() / tx_height) + (src.height() / tx_height));
- y2 = 1.0 - (src.y() / tx_height);
+extern QGLWidget *qt_gl_share_widget();
- q_vertexType vertexArray[4*2];
- q_vertexType texCoordArray[4*2];
+QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *prototype)
+{
+ Q_D(QGL2PaintEngineEx);
+ switch (type) {
+ case QPixmapFilter::ColorizeFilter:
+ if (!d->colorizeFilter)
+ d->colorizeFilter.reset(new QGLPixmapColorizeFilter);
+ return d->colorizeFilter.data();
- qt_add_rect_to_array(rect, vertexArray);
- qt_add_texcoords_to_array(x1, y2, x2, y1, texCoordArray);
+ case QPixmapFilter::BlurFilter: {
+ const QPixmapBlurFilter *proto = static_cast<const QPixmapBlurFilter *>(prototype);
+ if (proto->blurHints() & QGraphicsBlurEffect::AnimationHint) {
+ if (!d->animationBlurFilter)
+ d->animationBlurFilter.reset(new QGLPixmapBlurFilter(proto->blurHints()));
+ return d->animationBlurFilter.data();
+ }
+ if ((proto->blurHints() & QGraphicsBlurEffect::QualityHint) && proto->radius() > 5) {
+ if (!d->blurFilter)
+ d->blurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::QualityHint));
+ return d->blurFilter.data();
+ }
+ if (!d->fastBlurFilter)
+ d->fastBlurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::PerformanceHint));
+ return d->fastBlurFilter.data();
+ }
- glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
- glTexCoordPointer(2, q_vertexTypeEnum, 0, texCoordArray);
+ case QPixmapFilter::DropShadowFilter: {
+ const QPixmapDropShadowFilter *proto = static_cast<const QPixmapDropShadowFilter *>(prototype);
+ if (proto->blurRadius() <= 5) {
+ if (!d->fastDropShadowFilter)
+ d->fastDropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::PerformanceHint));
+ return d->fastDropShadowFilter.data();
+ }
+ if (!d->dropShadowFilter)
+ d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::QualityHint));
+ return d->dropShadowFilter.data();
+ }
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_VERTEX_ARRAY);
+ case QPixmapFilter::ConvolutionFilter:
+ if (!d->convolutionFilter)
+ d->convolutionFilter.reset(new QGLPixmapConvolutionFilter);
+ return d->convolutionFilter.data();
-#ifndef QT_OPENGL_ES
- glPopAttrib();
-#endif
-#endif
+ default: break;
+ }
+ return QPaintEngineEx::pixmapFilter(type, prototype);
}
static const char *qt_gl_colorize_filter =
- "uniform sampler2D texture;"
- "uniform vec3 color;"
- "void main(void)"
+ "uniform lowp vec4 colorizeColor;"
+ "uniform lowp float colorizeStrength;"
+ "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)"
"{"
- " vec2 coords = gl_TexCoord[0].st;"
- " vec4 src = texture2D(texture, coords);"
- " float gray = dot(src.rgb, vec3(0.212671, 0.715160, 0.072169));"
- " vec3 colorizeed = 1.0-((1.0-gray)*(1.0-color));"
- " gl_FragColor = vec4(colorizeed, src.a);"
+ " lowp vec4 srcPixel = texture2D(src, srcCoords);"
+ " lowp float gray = dot(srcPixel.rgb, vec3(0.212671, 0.715160, 0.072169));"
+ " lowp vec3 colorized = 1.0-((1.0-gray)*(1.0-colorizeColor.rgb));"
+ " return vec4(mix(srcPixel.rgb, colorized * srcPixel.a, colorizeStrength), srcPixel.a);"
"}";
QGLPixmapColorizeFilter::QGLPixmapColorizeFilter()
{
- m_program.addShader(QGLShader::FragmentShader, qt_gl_colorize_filter);
- m_program.link();
- m_program.enable();
- m_program.setUniformValue(m_program.uniformLocation("texture"), GLint(0)); // GL_TEXTURE_0
- m_colorUniform = m_program.uniformLocation("color");
+ setSource(qt_gl_colorize_filter);
}
-bool QGLPixmapColorizeFilter::processGL(QPainter *, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const
+bool QGLPixmapColorizeFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const
{
- bindTexture(src);
+ QGLPixmapColorizeFilter *filter = const_cast<QGLPixmapColorizeFilter *>(this);
- QColor col = color();
- m_program.enable();
- m_program.setUniformValue(m_colorUniform, col.redF(), col.greenF(), col.blueF());
-
- QRectF target = (srcRect.isNull() ? QRectF(src.rect()) : srcRect).translated(pos);
- qgl_drawTexture(target, src.width(), src.height(), srcRect);
- m_program.disable();
+ filter->setOnPainter(painter);
+ painter->drawPixmap(pos, src);
+ filter->removeFromPainter(painter);
return true;
}
+void QGLPixmapColorizeFilter::setUniforms(QGLShaderProgram *program)
+{
+ program->setUniformValue("colorizeColor", color());
+ program->setUniformValue("colorizeStrength", float(strength()));
+}
+
+void QGLPixmapConvolutionFilter::setUniforms(QGLShaderProgram *program)
+{
+ const qreal *kernel = convolutionKernel();
+ int kernelWidth = columns();
+ int kernelHeight = rows();
+ int kernelSize = kernelWidth * kernelHeight;
+
+ QVarLengthArray<GLfloat> matrix(kernelSize);
+ QVarLengthArray<GLfloat> offset(kernelSize * 2);
+
+ for(int i = 0; i < kernelSize; ++i)
+ matrix[i] = kernel[i];
+
+ for(int y = 0; y < kernelHeight; ++y) {
+ for(int x = 0; x < kernelWidth; ++x) {
+ offset[(y * kernelWidth + x) * 2] = x - (kernelWidth / 2);
+ offset[(y * kernelWidth + x) * 2 + 1] = (kernelHeight / 2) - y;
+ }
+ }
+
+ const qreal iw = 1.0 / m_srcSize.width();
+ const qreal ih = 1.0 / m_srcSize.height();
+ program->setUniformValue("inv_texture_size", iw, ih);
+ program->setUniformValueArray("matrix", matrix.constData(), kernelSize, 1);
+ program->setUniformValueArray("offset", offset.constData(), kernelSize, 2);
+}
+
// generates convolution filter code for arbitrary sized kernel
QByteArray QGLPixmapConvolutionFilter::generateConvolutionShader() const {
QByteArray code;
- code.append("uniform sampler2D texture;\n"
- "uniform vec2 inv_texture_size;\n"
- "uniform float matrix[");
- code.append(QByteArray::number(m_kernelWidth * m_kernelHeight));
+ int kernelWidth = columns();
+ int kernelHeight = rows();
+ int kernelSize = kernelWidth * kernelHeight;
+ code.append("uniform highp vec2 inv_texture_size;\n"
+ "uniform mediump float matrix[");
+ code.append(QByteArray::number(kernelSize));
code.append("];\n"
- "vec2 offset[");
- code.append(QByteArray::number(m_kernelWidth*m_kernelHeight));
- code.append("];\n"
- "void main(void) {\n");
-
- for(int y = 0; y < m_kernelHeight; y++) {
- for(int x = 0; x < m_kernelWidth; x++) {
- code.append(" offset[");
- code.append(QByteArray::number(y * m_kernelWidth + x));
- code.append("] = vec2(inv_texture_size.x * ");
- code.append(QByteArray::number(x-(int)(m_kernelWidth/2)));
- code.append(".0, inv_texture_size.y * ");
- code.append(QByteArray::number((int)(m_kernelHeight/2)-y));
- code.append(".0);\n");
- }
- }
+ "uniform highp vec2 offset[");
+ code.append(QByteArray::number(kernelSize));
+ code.append("];\n");
+ code.append("lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords) {\n");
code.append(" int i = 0;\n"
- " vec2 coords = gl_TexCoord[0].st;\n"
- " vec4 sum = vec4(0.0);\n"
+ " lowp vec4 sum = vec4(0.0);\n"
" for (i = 0; i < ");
- code.append(QByteArray::number(m_kernelWidth * m_kernelHeight));
+ code.append(QByteArray::number(kernelSize));
code.append("; i++) {\n"
- " vec4 tmp = texture2D(texture,coords+offset[i]);\n"
- " sum += matrix[i] * tmp;\n"
+ " sum += matrix[i] * texture2D(src,srcCoords+inv_texture_size*offset[i]);\n"
" }\n"
- " gl_FragColor = sum;\n"
+ " return sum;\n"
"}");
return code;
}
QGLPixmapConvolutionFilter::QGLPixmapConvolutionFilter()
- : m_program(0)
- , m_scaleUniform(0)
- , m_matrixUniform(0)
- , m_kernelWidth(0)
- , m_kernelHeight(0)
+ : m_prevKernelSize(-1)
{
}
QGLPixmapConvolutionFilter::~QGLPixmapConvolutionFilter()
{
- delete m_program;
}
-bool QGLPixmapConvolutionFilter::processGL(QPainter *, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const
+bool QGLPixmapConvolutionFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const
{
- QRectF target = (srcRect.isNull() ? QRectF(src.rect()) : srcRect).translated(pos);
+ QGLPixmapConvolutionFilter *filter = const_cast<QGLPixmapConvolutionFilter *>(this);
+
+ m_srcSize = src.size();
- bindTexture(src);
-#ifdef GL_CLAMP
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-#endif
- if (!m_program || m_kernelWidth != columns() || m_kernelHeight != rows()) {
- delete m_program;
+ int kernelSize = rows() * columns();
+ if (m_prevKernelSize == -1 || m_prevKernelSize != kernelSize) {
+ filter->setSource(generateConvolutionShader());
+ m_prevKernelSize = kernelSize;
+ }
- m_kernelWidth = columns();
- m_kernelHeight = rows();
+ filter->setOnPainter(painter);
+ painter->drawPixmap(pos, src, srcRect);
+ filter->removeFromPainter(painter);
- QByteArray code = generateConvolutionShader();
- m_program = new QGLShaderProgram();
- m_program->addShader(QGLShader::FragmentShader, code);
- m_program->link();
- m_scaleUniform = m_program->uniformLocation("inv_texture_size");
- m_matrixUniform = m_program->uniformLocation("matrix");
+ return true;
+}
+
+static const char *qt_gl_texture_sampling_helper =
+ "lowp float texture2DAlpha(lowp sampler2D src, highp vec2 srcCoords) {\n"
+ " return texture2D(src, srcCoords).a;\n"
+ "}\n";
+
+QGLPixmapBlurFilter::QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHints hints)
+ : m_animatedBlur(false)
+ , m_haveCached(false)
+ , m_cachedRadius(0)
+ , m_hints(hints)
+{
+}
+
+// should be even numbers as they will be divided by two
+static const int qCachedBlurLevels[] = { 6, 14, 30 };
+static const int qNumCachedBlurTextures = sizeof(qCachedBlurLevels) / sizeof(*qCachedBlurLevels);
+static const int qMaxCachedBlurLevel = qCachedBlurLevels[qNumCachedBlurTextures - 1];
+
+static qreal qLogBlurLevel(int level)
+{
+ static bool initialized = false;
+ static qreal logBlurLevelCache[qNumCachedBlurTextures];
+ if (!initialized) {
+ for (int i = 0; i < qNumCachedBlurTextures; ++i)
+ logBlurLevelCache[i] = qLn(qCachedBlurLevels[i]);
+ initialized = true;
}
+ return logBlurLevelCache[level];
+}
+
+class QGLBlurTextureInfo
+{
+public:
+ QGLBlurTextureInfo(QSize size, GLuint textureIds[])
+ : m_size(size)
+ {
+ for (int i = 0; i < qNumCachedBlurTextures; ++i)
+ m_textureIds[i] = textureIds[i];
+ }
+
+ ~QGLBlurTextureInfo()
+ {
+ glDeleteTextures(qNumCachedBlurTextures, m_textureIds);
+ }
+
+ QSize size() const { return m_size; }
+ GLuint textureId(int i) const { return m_textureIds[i]; }
+
+private:
+ GLuint m_textureIds[qNumCachedBlurTextures];
+ QSize m_size;
+};
+
+class QGLBlurTextureCache : public QObject
+{
+public:
+ static QGLBlurTextureCache *cacheForContext(const QGLContext *context);
+
+ QGLBlurTextureCache();
+ ~QGLBlurTextureCache();
+
+ QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap);
+ bool fitsInCache(const QPixmap &pixmap) const;
+ bool hasBlurTextureInfo(const QPixmap &pixmap) const;
+ void insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info);
+ void clearBlurTextureInfo(const QPixmap &pixmap);
+
+ void timerEvent(QTimerEvent *event);
+
+private:
+ static void pixmapDestroyed(QPixmap *pixmap);
+
+ QCache<quint64, QGLBlurTextureInfo > cache;
+
+ static QList<QGLBlurTextureCache *> blurTextureCaches;
+
+ int timerId;
+};
+
+QList<QGLBlurTextureCache *> QGLBlurTextureCache::blurTextureCaches;
+
+static void QGLBlurTextureCache_free(void *ptr)
+{
+ delete reinterpret_cast<QGLBlurTextureCache *>(ptr);
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_blur_texture_caches, (QGLBlurTextureCache_free))
+
+QGLBlurTextureCache::QGLBlurTextureCache()
+ : timerId(0)
+{
+ cache.setMaxCost(4 * 1024 * 1024);
+ blurTextureCaches.append(this);
+}
+
+QGLBlurTextureCache::~QGLBlurTextureCache()
+{
+ blurTextureCaches.removeAt(blurTextureCaches.indexOf(this));
+}
+
+void QGLBlurTextureCache::timerEvent(QTimerEvent *)
+{
+ killTimer(timerId);
+ timerId = 0;
+
+ cache.clear();
+}
+
+QGLBlurTextureCache *QGLBlurTextureCache::cacheForContext(const QGLContext *context)
+{
+ QGLBlurTextureCache *p = reinterpret_cast<QGLBlurTextureCache *>(qt_blur_texture_caches()->value(context));
+ if (!p) {
+ p = new QGLBlurTextureCache;
+ qt_blur_texture_caches()->insert(context, p);
+ }
+ return p;
+}
+
+QGLBlurTextureInfo *QGLBlurTextureCache::takeBlurTextureInfo(const QPixmap &pixmap)
+{
+ return cache.take(pixmap.cacheKey());
+}
+
+void QGLBlurTextureCache::clearBlurTextureInfo(const QPixmap &pixmap)
+{
+ cache.remove(pixmap.cacheKey());
+}
+
+bool QGLBlurTextureCache::hasBlurTextureInfo(const QPixmap &pixmap) const
+{
+ return cache.contains(pixmap.cacheKey());
+}
+
+void QGLBlurTextureCache::insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info)
+{
+ static bool hookAdded = false;
+ if (!hookAdded) {
+ QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(pixmapDestroyed);
+ hookAdded = true;
+ }
+
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmap);
+ cache.insert(pixmap.cacheKey(), info, pixmap.width() * pixmap.height());
+
+ if (timerId)
+ killTimer(timerId);
+
+ timerId = startTimer(1000);
+}
+
+bool QGLBlurTextureCache::fitsInCache(const QPixmap &pixmap) const
+{
+ return pixmap.width() * pixmap.height() <= cache.maxCost();
+}
+
+void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap)
+{
+ foreach (QGLBlurTextureCache *cache, blurTextureCaches) {
+ if (cache->hasBlurTextureInfo(*pixmap))
+ cache->clearBlurTextureInfo(*pixmap);
+ }
+}
+
+static const char *qt_gl_interpolate_filter =
+ "uniform lowp float interpolationValue;"
+ "uniform lowp sampler2D interpolateTarget;"
+ "uniform highp vec4 interpolateMapping;"
+ "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)"
+ "{"
+ " return mix(texture2D(interpolateTarget, interpolateMapping.xy + interpolateMapping.zw * srcCoords),"
+ " texture2D(src, srcCoords), interpolationValue);"
+ "}";
+
+static void initializeTexture(GLuint id, int width, int height)
+{
+ glBindTexture(GL_TEXTURE_2D, id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const
+{
+ QGLPixmapBlurFilter *filter = const_cast<QGLPixmapBlurFilter *>(this);
+
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx);
+
+ if ((m_hints & QGraphicsBlurEffect::AnimationHint) && blurTextureCache->fitsInCache(src)) {
+ QRect targetRect = src.rect().adjusted(-qMaxCachedBlurLevel, -qMaxCachedBlurLevel, qMaxCachedBlurLevel, qMaxCachedBlurLevel);
+ // ensure even dimensions (going to divide by two)
+ targetRect.setWidth((targetRect.width() + 1) & ~1);
+ targetRect.setHeight((targetRect.height() + 1) & ~1);
+
+ QGLBlurTextureInfo *info = 0;
+ if (blurTextureCache->hasBlurTextureInfo(src)) {
+ info = blurTextureCache->takeBlurTextureInfo(src);
+ } else {
+ m_animatedBlur = false;
+ m_hints = QGraphicsBlurEffect::QualityHint;
+ m_singlePass = false;
+
+ QGLFramebufferObjectFormat format;
+ format.setInternalTextureFormat(GLenum(GL_RGBA));
+ QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size() / 2, format, true);
+
+ if (!fbo)
+ return false;
+
+ QPainter fboPainter(fbo);
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(fboPainter.paintEngine());
+
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // ensure GL_LINEAR filtering is used for scaling down to half the size
+ fboPainter.setRenderHint(QPainter::SmoothPixmapTransform);
+ fboPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ fboPainter.drawPixmap(qMaxCachedBlurLevel / 2, qMaxCachedBlurLevel / 2,
+ targetRect.width() / 2 - qMaxCachedBlurLevel, targetRect.height() / 2 - qMaxCachedBlurLevel, src);
+
+ GLuint textures[qNumCachedBlurTextures]; // blur textures
+ glGenTextures(qNumCachedBlurTextures, textures);
+ GLuint temp; // temp texture
+ glGenTextures(1, &temp);
+
+ initializeTexture(temp, fbo->width(), fbo->height());
+ m_textureSize = fbo->size();
+
+ int currentBlur = 0;
+
+ QRect fboRect(0, 0, fbo->width(), fbo->height());
+ GLuint sourceTexture = fbo->texture();
+ for (int i = 0; i < qNumCachedBlurTextures; ++i) {
+ int targetBlur = qCachedBlurLevels[i] / 2;
+
+ int blurDelta = qRound(qSqrt(targetBlur * targetBlur - currentBlur * currentBlur));
+ QByteArray source = generateGaussianShader(blurDelta);
+ filter->setSource(source);
+
+ currentBlur = targetBlur;
+
+ // now we're going to be nasty and keep using the same FBO with different textures
+ glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, temp, 0);
+
+ m_horizontalBlur = true;
+ filter->setOnPainter(&fboPainter);
+ engine->drawTexture(fboRect, sourceTexture, fbo->size(), fboRect);
+ filter->removeFromPainter(&fboPainter);
+
+ sourceTexture = textures[i];
+ initializeTexture(sourceTexture, fbo->width(), fbo->height());
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, textures[i], 0);
+
+ m_horizontalBlur = false;
+ filter->setOnPainter(&fboPainter);
+ engine->drawTexture(fboRect, temp, fbo->size(), fboRect);
+ filter->removeFromPainter(&fboPainter);
+ }
+
+ glDeleteTextures(1, &temp);
+
+ // reattach the original FBO texture
+ glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, fbo->texture(), 0);
+
+ fboPainter.end();
+
+ qgl_fbo_pool()->release(fbo);
+
+ info = new QGLBlurTextureInfo(fboRect.size(), textures);
+ }
+
+ if (!m_haveCached || !m_animatedBlur) {
+ m_haveCached = true;
+ m_animatedBlur = true;
+ m_hints = QGraphicsBlurEffect::AnimationHint;
+ filter->setSource(qt_gl_interpolate_filter);
+ }
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine());
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+ filter->setOnPainter(painter);
+
+ qreal logRadius = qLn(radius());
+
+ int t;
+ for (t = -1; t < qNumCachedBlurTextures - 2; ++t) {
+ if (logRadius < qLogBlurLevel(t+1))
+ break;
+ }
+
+ qreal logBase = t >= 0 ? qLogBlurLevel(t) : 0;
+ m_t = qBound(qreal(0), (logRadius - logBase) / (qLogBlurLevel(t+1) - logBase), qreal(1));
+
+ m_textureSize = info->size();
+
+ glActiveTexture(GL_TEXTURE0 + 3);
+ if (t >= 0) {
+ glBindTexture(GL_TEXTURE_2D, info->textureId(t));
+ m_targetSize = info->size();
+ } else {
+ QGLTexture *texture =
+ ctx->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption
+ | QGLContext::CanFlipNativePixmapBindOption);
+ m_targetSize = src.size();
+ if (!(texture->options & QGLContext::InvertedYBindOption))
+ m_targetSize.setHeight(-m_targetSize.height());
+ }
+
+ // restrict the target rect to the max of the radii we are interpolating between
+ int radiusDelta = qMaxCachedBlurLevel - qCachedBlurLevels[t+1];
+ targetRect = targetRect.translated(pos.toPoint()).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta);
+
+ radiusDelta /= 2;
+ QRect sourceRect = QRect(QPoint(), m_textureSize).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta);
+
+ engine->drawTexture(targetRect, info->textureId(t+1), m_textureSize, sourceRect);
+
+ glActiveTexture(GL_TEXTURE0 + 3);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ filter->removeFromPainter(painter);
+ blurTextureCache->insertBlurTextureInfo(src, info);
+
+ return true;
+ }
+
+ if (blurTextureCache->hasBlurTextureInfo(src))
+ blurTextureCache->clearBlurTextureInfo(src);
+
+ int actualRadius = qRound(radius());
+ int filterRadius = actualRadius;
+ int fastRadii[] = { 1, 2, 3, 5, 8, 15, 25 };
+ if (!(m_hints & QGraphicsBlurEffect::QualityHint)) {
+ uint i = 0;
+ for (; i < (sizeof(fastRadii)/sizeof(*fastRadii))-1; ++i) {
+ if (fastRadii[i+1] > filterRadius)
+ break;
+ }
+ filterRadius = fastRadii[i];
+ }
+
+ m_singlePass = filterRadius <= 3;
+
+ if (!m_haveCached || m_animatedBlur || filterRadius != m_cachedRadius) {
+ // Only regenerate the shader from source if parameters have changed.
+ m_haveCached = true;
+ m_animatedBlur = false;
+ m_cachedRadius = filterRadius;
+ QByteArray source = generateGaussianShader(filterRadius, m_singlePass);
+ filter->setSource(source);
+ }
+
+ QRect targetRect = QRectF(src.rect()).translated(pos).adjusted(-actualRadius, -actualRadius, actualRadius, actualRadius).toAlignedRect();
+
+ if (m_singlePass) {
+ // prepare for updateUniforms
+ m_textureSize = src.size();
+
+ // ensure GL_LINEAR filtering is used
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+ filter->setOnPainter(painter);
+ QBrush pixmapBrush = src;
+ pixmapBrush.setTransform(QTransform::fromTranslate(pos.x(), pos.y()));
+ painter->fillRect(targetRect, pixmapBrush);
+ filter->removeFromPainter(painter);
+ } else {
+ QGLFramebufferObjectFormat format;
+ format.setInternalTextureFormat(GLenum(src.hasAlphaChannel() ? GL_RGBA : GL_RGB));
+ QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size(), format);
+
+ if (!fbo)
+ return false;
+
+ // prepare for updateUniforms
+ m_textureSize = src.size();
+
+ // horizontal pass, to pixmap
+ m_horizontalBlur = true;
+
+ QPainter fboPainter(fbo);
+
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // ensure GL_LINEAR filtering is used
+ fboPainter.setRenderHint(QPainter::SmoothPixmapTransform);
+ fboPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ filter->setOnPainter(&fboPainter);
+ QBrush pixmapBrush = src;
+ pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius));
+ fboPainter.fillRect(QRect(0, 0, targetRect.width(), targetRect.height()), pixmapBrush);
+ filter->removeFromPainter(&fboPainter);
+ fboPainter.end();
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine());
+
+ // vertical pass, to painter
+ m_horizontalBlur = false;
+ m_textureSize = fbo->size();
+
+ painter->save();
+ // ensure GL_LINEAR filtering is used
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+ filter->setOnPainter(painter);
+ engine->drawTexture(targetRect, fbo->texture(), fbo->size(), QRect(QPoint(), targetRect.size()).translated(0, fbo->height() - targetRect.height()));
+ filter->removeFromPainter(painter);
+ painter->restore();
+
+ qgl_fbo_pool()->release(fbo);
+ }
+
+ return true;
+}
+
+void QGLPixmapBlurFilter::setUniforms(QGLShaderProgram *program)
+{
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ if (m_animatedBlur) {
+ program->setUniformValue("interpolateTarget", 3);
+ program->setUniformValue("interpolationValue", GLfloat(m_t));
+
+ if (m_textureSize == m_targetSize) {
+ program->setUniformValue("interpolateMapping", 0.0f, 0.0f, 1.0f, 1.0f);
+ } else {
+ float offsetX = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.width());
+ float offsetY = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.height());
+
+ if (m_targetSize.height() < 0)
+ offsetY = 1 + offsetY;
+
+ float scaleX = 2.0f * qreal(m_textureSize.width()) / qreal(m_targetSize.width());
+ float scaleY = 2.0f * qreal(m_textureSize.height()) / qreal(m_targetSize.height());
+
+ program->setUniformValue("interpolateMapping", offsetX, offsetY, scaleX, scaleY);
+ }
+
+ return;
+ }
+
+ if (m_hints & QGraphicsBlurEffect::QualityHint) {
+ if (m_singlePass)
+ program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height());
+ else if (m_horizontalBlur)
+ program->setUniformValue("delta", 1.0 / m_textureSize.width(), 0.0);
+ else
+ program->setUniformValue("delta", 0.0, 1.0 / m_textureSize.height());
+ } else {
+ qreal blur = radius() / qreal(m_cachedRadius);
+
+ if (m_singlePass)
+ program->setUniformValue("delta", blur / m_textureSize.width(), blur / m_textureSize.height());
+ else if (m_horizontalBlur)
+ program->setUniformValue("delta", blur / m_textureSize.width(), 0.0);
+ else
+ program->setUniformValue("delta", 0.0, blur / m_textureSize.height());
+ }
+}
+
+static inline qreal gaussian(qreal dx, qreal sigma)
+{
+ return exp(-dx * dx / (2 * sigma * sigma)) / (Q_2PI * sigma * sigma);
+}
+
+QByteArray QGLPixmapBlurFilter::generateGaussianShader(int radius, bool singlePass, bool dropShadow)
+{
+ Q_ASSERT(radius >= 1);
+
+ radius = qMin(127, radius);
+
+ static QCache<uint, QByteArray> shaderSourceCache;
+ uint key = radius | (int(singlePass) << 7) | (int(dropShadow) << 8);
+ QByteArray *cached = shaderSourceCache.object(key);
+ if (cached)
+ return *cached;
+
+ QByteArray source;
+ source.reserve(1000);
+ source.append(qt_gl_texture_sampling_helper);
+
+ source.append("uniform highp vec2 delta;\n");
+ if (dropShadow)
+ source.append("uniform mediump vec4 shadowColor;\n");
+ source.append("lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords) {\n");
+
+ QVector<qreal> sampleOffsets;
+ QVector<qreal> weights;
+
+ QVector<qreal> gaussianComponents;
+
+ qreal sigma = radius / 1.65;
+
+ qreal sum = 0;
+ for (int i = -radius; i < radius; ++i) {
+ float value = gaussian(i, sigma);
+ gaussianComponents << value;
+ sum += value;
+ }
+
+ // normalize
+ for (int i = 0; i < gaussianComponents.size(); ++i)
+ gaussianComponents[i] /= sum;
+
+ for (int i = 0; i < gaussianComponents.size() - 1; i += 2) {
+ qreal weight = gaussianComponents.at(i) + gaussianComponents.at(i + 1);
+ qreal offset = i - radius + gaussianComponents.at(i + 1) / weight;
+
+ sampleOffsets << offset;
+ weights << weight;
+ }
+
+ int limit = sampleOffsets.size();
+ if (singlePass)
+ limit *= limit;
+
+ QByteArray baseCoordinate = "srcCoords";
+
+ for (int i = 0; i < limit; ++i) {
+ QByteArray coordinate = baseCoordinate;
+
+ qreal weight;
+ if (singlePass) {
+ const int xIndex = i % sampleOffsets.size();
+ const int yIndex = i / sampleOffsets.size();
+
+ const qreal deltaX = sampleOffsets.at(xIndex);
+ const qreal deltaY = sampleOffsets.at(yIndex);
+ weight = weights.at(xIndex) * weights.at(yIndex);
+
+ if (!qFuzzyCompare(deltaX, deltaY)) {
+ coordinate.append(" + vec2(delta.x * float(");
+ coordinate.append(QByteArray::number(deltaX));
+ coordinate.append("), delta.y * float(");
+ coordinate.append(QByteArray::number(deltaY));
+ coordinate.append("))");
+ } else if (!qFuzzyIsNull(deltaX)) {
+ coordinate.append(" + delta * float(");
+ coordinate.append(QByteArray::number(deltaX));
+ coordinate.append(")");
+ }
+ } else {
+ const qreal delta = sampleOffsets.at(i);
+ weight = weights.at(i);
+ if (!qFuzzyIsNull(delta)) {
+ coordinate.append(" + delta * float(");
+ coordinate.append(QByteArray::number(delta));
+ coordinate.append(")");
+ }
+ }
+
+ if (i == 0) {
+ if (dropShadow)
+ source.append(" mediump float sample = ");
+ else
+ source.append(" mediump vec4 sample = ");
+ } else {
+ if (dropShadow)
+ source.append(" sample += ");
+ else
+ source.append(" sample += ");
+ }
+
+ source.append("texture2D(src, ");
+ source.append(coordinate);
+ source.append(")");
+
+ if (dropShadow)
+ source.append(".a");
+
+ if (!qFuzzyCompare(weight, qreal(1))) {
+ source.append(" * float(");
+ source.append(QByteArray::number(weight));
+ source.append(");\n");
+ } else {
+ source.append(";\n");
+ }
+ }
+
+ source.append(" return ");
+ if (dropShadow)
+ source.append("shadowColor * ");
+ source.append("sample;\n");
+ source.append("}\n");
+
+ cached = new QByteArray(source);
+ shaderSourceCache.insert(key, cached);
+
+ return source;
+}
+
+QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHints hints)
+ : m_haveCached(false)
+ , m_cachedRadius(0)
+ , m_hints(hints)
+{
+}
+
+bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const
+{
+ QGLPixmapDropShadowFilter *filter = const_cast<QGLPixmapDropShadowFilter *>(this);
+
+ int actualRadius = qRound(blurRadius());
+ int filterRadius = actualRadius;
+ m_singlePass = filterRadius <= 3;
+
+ if (!m_haveCached || filterRadius != m_cachedRadius) {
+ // Only regenerate the shader from source if parameters have changed.
+ m_haveCached = true;
+ m_cachedRadius = filterRadius;
+ QByteArray source = QGLPixmapBlurFilter::generateGaussianShader(filterRadius, m_singlePass, true);
+ filter->setSource(source);
+ }
+
+ QRect targetRect = QRectF(src.rect()).translated(pos + offset()).adjusted(-actualRadius, -actualRadius, actualRadius, actualRadius).toAlignedRect();
+
+ if (m_singlePass) {
+ // prepare for updateUniforms
+ m_textureSize = src.size();
+
+ painter->save();
+ // ensure GL_LINEAR filtering is used
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+ filter->setOnPainter(painter);
+ QBrush pixmapBrush = src;
+ pixmapBrush.setTransform(QTransform::fromTranslate(pos.x() + offset().x(), pos.y() + offset().y()));
+ painter->fillRect(targetRect, pixmapBrush);
+ filter->removeFromPainter(painter);
+ painter->restore();
+ } else {
+ QGLFramebufferObjectFormat format;
+ format.setInternalTextureFormat(GLenum(src.hasAlphaChannel() ? GL_RGBA : GL_RGB));
+ QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size(), format);
+
+ if (!fbo)
+ return false;
+
+ // prepare for updateUniforms
+ m_textureSize = src.size();
+
+ // horizontal pass, to pixmap
+ m_horizontalBlur = true;
+
+ QPainter fboPainter(fbo);
+
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // ensure GL_LINEAR filtering is used
+ fboPainter.setRenderHint(QPainter::SmoothPixmapTransform);
+ fboPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ filter->setOnPainter(&fboPainter);
+ QBrush pixmapBrush = src;
+ pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius));
+ fboPainter.fillRect(QRect(0, 0, targetRect.width(), targetRect.height()), pixmapBrush);
+ filter->removeFromPainter(&fboPainter);
+ fboPainter.end();
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine());
+
+ // vertical pass, to painter
+ m_horizontalBlur = false;
+ m_textureSize = fbo->size();
+
+ painter->save();
+ // ensure GL_LINEAR filtering is used
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+ filter->setOnPainter(painter);
+ engine->drawTexture(targetRect, fbo->texture(), fbo->size(), QRectF(0, fbo->height() - targetRect.height(), targetRect.width(), targetRect.height()));
+ filter->removeFromPainter(painter);
+ painter->restore();
+
+ qgl_fbo_pool()->release(fbo);
+ }
+
+ // Now draw the actual pixmap over the top.
+ painter->drawPixmap(pos, src, srcRect);
- const qreal *kernel = convolutionKernel();
- GLfloat *conv = new GLfloat[m_kernelWidth * m_kernelHeight];
- for(int i = 0; i < m_kernelWidth * m_kernelHeight; ++i)
- conv[i] = kernel[i];
-
- const qreal iw = 1.0 / src.width();
- const qreal ih = 1.0 / src.height();
- m_program->enable();
- m_program->setUniformValue(m_scaleUniform, iw, ih);
- m_program->setUniformValueArray(m_matrixUniform, conv, m_kernelWidth * m_kernelHeight, 1);
-
- qgl_drawTexture(target, src.width(), src.height(), boundingRectFor(srcRect));
- m_program->disable();
return true;
}
+void QGLPixmapDropShadowFilter::setUniforms(QGLShaderProgram *program)
+{
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ QColor col = color();
+ if (m_horizontalBlur && !m_singlePass) {
+ program->setUniformValue("shadowColor", 1.0f, 1.0f, 1.0f, 1.0f);
+ } else {
+ qreal alpha = col.alphaF();
+ program->setUniformValue("shadowColor", col.redF() * alpha,
+ col.greenF() * alpha,
+ col.blueF() * alpha,
+ alpha);
+ }
+
+ if (m_hints & QGraphicsBlurEffect::QualityHint) {
+ if (m_singlePass)
+ program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height());
+ else if (m_horizontalBlur)
+ program->setUniformValue("delta", 1.0 / m_textureSize.width(), 0.0);
+ else
+ program->setUniformValue("delta", 0.0, 1.0 / m_textureSize.height());
+ } else {
+ qreal blur = blurRadius() / qreal(m_cachedRadius);
+
+ if (m_singlePass)
+ program->setUniformValue("delta", blur / m_textureSize.width(), blur / m_textureSize.height());
+ else if (m_horizontalBlur)
+ program->setUniformValue("delta", blur / m_textureSize.width(), 0.0);
+ else
+ program->setUniformValue("delta", 0.0, blur / m_textureSize.height());
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qglpixmapfilter_p.h b/src/opengl/qglpixmapfilter_p.h
index 0b0ebdb90..0ef3eb572 100644
--- a/src/opengl/qglpixmapfilter_p.h
+++ b/src/opengl/qglpixmapfilter_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/qglscreen_qws.cpp b/src/opengl/qglscreen_qws.cpp
index 41c35946b..8ca9919c7 100644
--- a/src/opengl/qglscreen_qws.cpp
+++ b/src/opengl/qglscreen_qws.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/qglscreen_qws.h b/src/opengl/qglscreen_qws.h
index 88b041c10..a2f4a5b65 100644
--- a/src/opengl/qglscreen_qws.h
+++ b/src/opengl/qglscreen_qws.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp
index e3627ffd2..b4191dcc3 100644
--- a/src/opengl/qglshaderprogram.cpp
+++ b/src/opengl/qglshaderprogram.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -42,6 +42,7 @@
#include "qglshaderprogram.h"
#include "qglextensions_p.h"
#include "qgl_p.h"
+#include <QtCore/private/qobject_p.h>
#include <QtCore/qdebug.h>
#include <QtCore/qfile.h>
#include <QtCore/qvarlengtharray.h>
@@ -55,6 +56,7 @@ QT_BEGIN_NAMESPACE
\class QGLShaderProgram
\brief The QGLShaderProgram class allows OpenGL shader programs to be linked and used.
\since 4.6
+ \ingroup painting-3D
\section1 Introduction
@@ -67,18 +69,9 @@ QT_BEGIN_NAMESPACE
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 QGLContext by calling
- QGLShaderProgram::enable():
-
- \code
- QGLShader shader(QGLShader::VertexShader);
- shader.compile(code);
-
- QGLShaderProgram program(context);
- program.addShader(shader);
- program.link();
+ QGLShaderProgram::bind():
- program.enable();
- \endcode
+ \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 0
\section1 Writing portable shaders
@@ -103,76 +96,15 @@ QT_BEGIN_NAMESPACE
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
- \code
- program.addShader(QGLShader::VertexShader,
- "attribute highp vec4 vertex;\n"
- "attribute mediump mat4 matrix;\n"
- "void main(void)\n"
- "{\n"
- " gl_Position = matrix * vertex;\n"
- "}");
- program.addShader(QGLShader::FragmentShader,
- "uniform mediump vec4 color;\n"
- "void main(void)\n"
- "{\n"
- " gl_FragColor = color;\n"
- "}");
- program.link();
- program.enable();
-
- int vertexLocation = program.attributeLocation("vertex");
- int matrixLocation = program.attributeLocation("matrix");
- int colorLocation = program.uniformLocation("color");
- \endcode
+ \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 1
With the above shader program active, we can draw a green triangle
as follows:
- \code
- static GLfloat const triangleVertices[] = {
- 60.0f, 10.0f, 0.0f,
- 110.0f, 110.0f, 0.0f,
- 10.0f, 110.0f, 0.0f
- };
-
- QColor color(0, 255, 0, 255);
-
- QMatrix4x4 pmvMatrix;
- pmvMatrix.ortho(rect());
-
- program.setAttributeArray(vertexLocation, triangleVertices, 3);
- program.setUniformValue(matrixLocation, pmvMatrix);
- program.setUniformValue(colorLocation, color);
-
- glDrawArrays(GL_TRIANGLES, 0, 3);
- \endcode
-
- \section1 Partial shaders
-
- Desktop GLSL can attach an arbitrary number of vertex and fragment
- shaders to a shader program. Embedded GLSL/ES on the other hand
- supports only a single shader of each type on a shader program.
-
- Multiple shaders of the same type can be useful when large libraries
- of shaders are needed. Common functions can be factored out into
- library shaders that can be reused in multiple shader programs.
-
- To support this use of shaders, the application programmer can
- create shaders with the QGLShader::PartialVertexShader and
- QGLShader::PartialFragmentShader types. These types direct
- QGLShader and QGLShaderProgram to delay shader compilation until
- link time.
-
- When link() is called, the sources for the partial shaders are
- concatenated, and a single vertex or fragment shader is compiled
- and linked into the shader program.
-
- It is more efficient to use the QGLShader::VertexShader and
- QGLShader::FragmentShader when there is only one shader of that
- type in the program.
+ \snippet doc/src/snippets/code/src_opengl_qglshaderprogram.cpp 2
\sa QGLShader
*/
@@ -181,6 +113,7 @@ QT_BEGIN_NAMESPACE
\class QGLShader
\brief The QGLShader 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).
@@ -192,13 +125,11 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \enum QGLShader::ShaderType
+ \enum QGLShader::ShaderTypeBit
This enum specifies the type of QGLShader that is being created.
- \value VertexShader Vertex shader written in the OpenGL Shading Language (GLSL).
- \value FragmentShader Fragment shader written in the OpenGL Shading Language (GLSL).
- \value PartialVertexShader Partial vertex shader that will be concatenated with all other partial vertex shaders at link time.
- \value PartialFragmentShader Partial fragment shader that will be concatenated with all other partial fragment shaders at link time.
+ \value Vertex Vertex shader written in the OpenGL Shading Language (GLSL).
+ \value Fragment Fragment shader written in the OpenGL Shading Language (GLSL).
*/
#ifndef GL_FRAGMENT_SHADER
@@ -241,45 +172,46 @@ QT_BEGIN_NAMESPACE
#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
#endif
-class QGLShaderPrivate
+class QGLShaderPrivate : public QObjectPrivate
{
+ Q_DECLARE_PUBLIC(QGLShader)
public:
- QGLShaderPrivate(QGLShader::ShaderType type, const QGLContext *ctx)
- : context(ctx)
- , shader(0)
+ QGLShaderPrivate(const QGLContext *context, QGLShader::ShaderType type)
+ : shaderGuard(context)
, shaderType(type)
, compiled(false)
- , isPartial(type == QGLShader::PartialVertexShader ||
- type == QGLShader::PartialFragmentShader)
- , hasPartialSource(false)
{
}
+ ~QGLShaderPrivate();
- const QGLContext *context;
- GLuint shader;
+ QGLSharedResourceGuard shaderGuard;
QGLShader::ShaderType shaderType;
bool compiled;
- bool isPartial;
- bool hasPartialSource;
QString log;
- QByteArray partialSource;
bool create();
bool compile(QGLShader *q);
+ void deleteShader();
};
-#define ctx context
+#define ctx shaderGuard.context()
+
+QGLShaderPrivate::~QGLShaderPrivate()
+{
+ if (shaderGuard.id()) {
+ QGLShareContextScope scope(shaderGuard.context());
+ glDeleteShader(shaderGuard.id());
+ }
+}
bool QGLShaderPrivate::create()
{
- if (isPartial)
- return true;
- if (!context)
- context = QGLContext::currentContext();
+ const QGLContext *context = shaderGuard.context();
if (!context)
return false;
if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
- if (shaderType == QGLShader::VertexShader)
+ GLuint shader;
+ if (shaderType == QGLShader::Vertex)
shader = glCreateShader(GL_VERTEX_SHADER);
else
shader = glCreateShader(GL_FRAGMENT_SHADER);
@@ -287,6 +219,7 @@ bool QGLShaderPrivate::create()
qWarning() << "QGLShader: could not create shader";
return false;
}
+ shaderGuard.setId(shader);
return true;
} else {
return false;
@@ -295,11 +228,7 @@ bool QGLShaderPrivate::create()
bool QGLShaderPrivate::compile(QGLShader *q)
{
- // Partial shaders are compiled during QGLShaderProgram::link().
- if (isPartial && hasPartialSource) {
- compiled = true;
- return true;
- }
+ GLuint shader = shaderGuard.id();
if (!shader)
return false;
glCompileShader(shader);
@@ -323,137 +252,59 @@ bool QGLShaderPrivate::compile(QGLShader *q)
return compiled;
}
+void QGLShaderPrivate::deleteShader()
+{
+ if (shaderGuard.id()) {
+ glDeleteShader(shaderGuard.id());
+ shaderGuard.setId(0);
+ }
+}
+
#undef ctx
-#define ctx d->context
+#define ctx d->shaderGuard.context()
/*!
Constructs a new QGLShader object of the specified \a type
and attaches it to \a parent. If shader programs are not supported,
- QGLShaderProgram::hasShaderPrograms() will return false.
+ QGLShaderProgram::hasOpenGLShaderPrograms() will return false.
- This constructor is normally followed by a call to compile()
- or compileFile().
+ This constructor is normally followed by a call to compileSourceCode()
+ or compileSourceFile().
The shader will be associated with the current QGLContext.
- \sa compile(), compileFile()
+ \sa compileSourceCode(), compileSourceFile()
*/
QGLShader::QGLShader(QGLShader::ShaderType type, QObject *parent)
- : QObject(parent)
+ : QObject(*new QGLShaderPrivate(QGLContext::currentContext(), type), parent)
{
- d = new QGLShaderPrivate(type, QGLContext::currentContext());
+ Q_D(QGLShader);
d->create();
}
/*!
- Constructs a new QGLShader object from the source code in \a fileName
- and attaches it to \a parent. If the filename ends in \c{.fsh},
- it is assumed to be a fragment shader, otherwise it is assumed to
- be a vertex shader (normally the extension is \c{.vsh} for vertex shaders).
- If the shader could not be loaded, then isCompiled() will return false.
-
- The shader will be associated with the current QGLContext.
-
- \sa isCompiled()
-*/
-QGLShader::QGLShader(const QString& fileName, QObject *parent)
- : QObject(parent)
-{
- if (fileName.endsWith(QLatin1String(".fsh"), Qt::CaseInsensitive))
- d = new QGLShaderPrivate(QGLShader::FragmentShader, QGLContext::currentContext());
- else
- d = new QGLShaderPrivate(QGLShader::VertexShader, QGLContext::currentContext());
- if (d->create() && !compileFile(fileName)) {
- if (d->shader)
- glDeleteShader(d->shader);
- d->shader = 0;
- }
-}
-
-/*!
- Constructs a new QGLShader object of the specified \a type from the
- source code in \a fileName and attaches it to \a parent.
- If the shader could not be loaded, then isCompiled() will return false.
-
- The shader will be associated with the current QGLContext.
-
- \sa isCompiled()
-*/
-QGLShader::QGLShader
- (const QString& fileName, QGLShader::ShaderType type, QObject *parent)
- : QObject(parent)
-{
- d = new QGLShaderPrivate(type, QGLContext::currentContext());
- if (d->create() && !compileFile(fileName)) {
- if (d->shader)
- glDeleteShader(d->shader);
- d->shader = 0;
- }
-}
-
-/*!
Constructs a new QGLShader object of the specified \a type
and attaches it to \a parent. If shader programs are not supported,
- then QGLShaderProgram::hasShaderPrograms() will return false.
+ then QGLShaderProgram::hasOpenGLShaderPrograms() will return false.
- This constructor is normally followed by a call to compile()
- or compileFile().
+ This constructor is normally followed by a call to compileSourceCode()
+ or compileSourceFile().
The shader will be associated with \a context.
- \sa compile(), compileFile()
+ \sa compileSourceCode(), compileSourceFile()
*/
QGLShader::QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent)
- : QObject(parent)
-{
- d = new QGLShaderPrivate(type, context);
- d->create();
-}
-
-/*!
- Constructs a new QGLShader object from the source code in \a fileName
- and attaches it to \a parent. If the filename ends in \c{.fsh},
- it is assumed to be a fragment shader, otherwise it is assumed to
- be a vertex shader (normally the extension is \c{.vsh} for vertex shaders).
- If the shader could not be loaded, then isCompiled() will return false.
-
- The shader will be associated with \a context.
-
- \sa isCompiled()
-*/
-QGLShader::QGLShader(const QString& fileName, const QGLContext *context, QObject *parent)
- : QObject(parent)
-{
- if (fileName.endsWith(QLatin1String(".fsh"), Qt::CaseInsensitive))
- d = new QGLShaderPrivate(QGLShader::FragmentShader, context);
- else
- d = new QGLShaderPrivate(QGLShader::VertexShader, context);
- if (d->create() && !compileFile(fileName)) {
- if (d->shader)
- glDeleteShader(d->shader);
- d->shader = 0;
- }
-}
-
-/*!
- Constructs a new QGLShader object of the specified \a type from the
- source code in \a fileName and attaches it to \a parent.
- If the shader could not be loaded, then isCompiled() will return false.
-
- The shader will be associated with \a context.
-
- \sa isCompiled()
-*/
-QGLShader::QGLShader
- (const QString& fileName, QGLShader::ShaderType type, const QGLContext *context, QObject *parent)
- : QObject(parent)
+ : QObject(*new QGLShaderPrivate(context ? context : QGLContext::currentContext(), type), parent)
{
- d = new QGLShaderPrivate(type, context);
- if (d->create() && !compileFile(fileName)) {
- if (d->shader)
- glDeleteShader(d->shader);
- d->shader = 0;
+ Q_D(QGLShader);
+#ifndef QT_NO_DEBUG
+ if (context && !QGLContext::areSharing(context, QGLContext::currentContext())) {
+ qWarning("QGLShader::QGLShader: \'context\' must be the current context or sharing with it.");
+ return;
}
+#endif
+ d->create();
}
/*!
@@ -463,9 +314,6 @@ QGLShader::QGLShader
*/
QGLShader::~QGLShader()
{
- if (d->shader)
- glDeleteShader(d->shader);
- delete d;
}
/*!
@@ -473,6 +321,7 @@ QGLShader::~QGLShader()
*/
QGLShader::ShaderType QGLShader::shaderType() const
{
+ Q_D(const QGLShader);
return d->shaderType;
}
@@ -487,30 +336,59 @@ static const char qualifierDefines[] =
"#define highp\n";
#endif
+// The "highp" qualifier doesn't exist in fragment shaders
+// on all ES platforms. When it doesn't exist, use "mediump".
+#ifdef QT_OPENGL_ES
+#define QGL_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.
- If shaderType() is PartialVertexShader or PartialFragmentShader,
- then this function will always return true, even if the source code
- is invalid. Partial shaders are compiled when QGLShaderProgram::link()
- is called.
-
- \sa compileFile()
-*/
-bool QGLShader::compile(const char *source)
-{
- if (d->isPartial) {
- d->partialSource = QByteArray(source);
- d->hasPartialSource = true;
- return d->compile(this);
- } else if (d->shader) {
- QVarLengthArray<const char *> src;
+ \sa compileSourceFile()
+*/
+bool QGLShader::compileSourceCode(const char *source)
+{
+ Q_D(QGLShader);
+ if (d->shaderGuard.id()) {
+ QVarLengthArray<const char *, 4> src;
+ QVarLengthArray<GLint, 4> 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 QGL_DEFINE_QUALIFIERS
src.append(qualifierDefines);
+ srclen.append(GLint(sizeof(qualifierDefines) - 1));
+#endif
+#ifdef QGL_REDEFINE_HIGHP
+ if (d->shaderType == Fragment) {
+ src.append(redefineHighp);
+ srclen.append(GLint(sizeof(redefineHighp) - 1));
+ }
#endif
- src.append(source);
- glShaderSource(d->shader, src.size(), src.data(), 0);
+ src.append(source + headerLen);
+ srclen.append(GLint(qstrlen(source + headerLen)));
+ glShaderSource(d->shaderGuard.id(), src.size(), src.data(), srclen.data());
return d->compile(this);
} else {
return false;
@@ -523,16 +401,11 @@ bool QGLShader::compile(const char *source)
Sets the \a source code for this shader and compiles it.
Returns true if the source was successfully compiled, false otherwise.
- If shaderType() is PartialVertexShader or PartialFragmentShader,
- then this function will always return true, even if the source code
- is invalid. Partial shaders are compiled when QGLShaderProgram::link()
- is called.
-
- \sa compileFile()
+ \sa compileSourceFile()
*/
-bool QGLShader::compile(const QByteArray& source)
+bool QGLShader::compileSourceCode(const QByteArray& source)
{
- return compile(source.constData());
+ return compileSourceCode(source.constData());
}
/*!
@@ -541,16 +414,11 @@ bool QGLShader::compile(const QByteArray& source)
Sets the \a source code for this shader and compiles it.
Returns true if the source was successfully compiled, false otherwise.
- If shaderType() is PartialVertexShader or PartialFragmentShader,
- then this function will always return true, even if the source code
- is invalid. Partial shaders are compiled when QGLShaderProgram::link()
- is called.
-
- \sa compileFile()
+ \sa compileSourceFile()
*/
-bool QGLShader::compile(const QString& source)
+bool QGLShader::compileSourceCode(const QString& source)
{
- return compile(source.toLatin1().constData());
+ return compileSourceCode(source.toLatin1().constData());
}
/*!
@@ -558,14 +426,9 @@ bool QGLShader::compile(const QString& source)
and compiles it. Returns true if the file could be opened and the
source compiled, false otherwise.
- If shaderType() is PartialVertexShader or PartialFragmentShader,
- then this function will always return true, even if the source code
- is invalid. Partial shaders are compiled when QGLShaderProgram::link()
- is called.
-
- \sa compile()
+ \sa compileSourceCode()
*/
-bool QGLShader::compileFile(const QString& fileName)
+bool QGLShader::compileSourceFile(const QString& fileName)
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly)) {
@@ -574,113 +437,27 @@ bool QGLShader::compileFile(const QString& fileName)
}
QByteArray contents = file.readAll();
- return compile(contents.constData());
-}
-
-/*!
- Sets the binary code for this shader to the \a length bytes from
- the array \a binary. The \a format specifies how the binary data
- should be interpreted by the OpenGL engine. Returns true if the
- binary was set on the shader; false otherwise.
-
- This function cannot be used with PartialVertexShader or
- PartialFragmentShader.
-
- If this function succeeds, then the shader will be considered compiled.
-
- \sa shaderBinaryFormats()
-*/
-bool QGLShader::setShaderBinary(GLenum format, const void *binary, int length)
-{
-#if !defined(QT_OPENGL_ES_2)
- if (!glShaderBinary)
- return false;
-#endif
- if (d->isPartial || !d->shader)
- return false;
- glGetError(); // Clear error state.
- glShaderBinary(1, &(d->shader), format, binary, length);
- d->compiled = (glGetError() == GL_NO_ERROR);
- return d->compiled;
-}
-
-/*!
- Sets the binary code for this shader to the \a length bytes from
- the array \a binary. The \a format specifies how the binary data
- should be interpreted by the OpenGL engine. Returns true if the
- binary was set on the shader; false otherwise.
-
- The \a otherShader will also have binary code set on it. This is
- for the case where \a binary contains both vertex and fragment
- shader code.
-
- This function cannot be used with PartialVertexShader or
- PartialFragmentShader.
-
- If this function succeeds, then the shader will be considered compiled.
-
- \sa shaderBinaryFormats()
-*/
-bool QGLShader::setShaderBinary
- (QGLShader& otherShader, GLenum format, const void *binary, int length)
-{
-#if !defined(QT_OPENGL_ES_2)
- if (!glShaderBinary)
- return false;
-#endif
- if (d->isPartial || !d->shader)
- return false;
- if (otherShader.d->isPartial || !otherShader.d->shader)
- return false;
- glGetError(); // Clear error state.
- GLuint shaders[2];
- shaders[0] = d->shader;
- shaders[1] = otherShader.d->shader;
- glShaderBinary(2, shaders, format, binary, length);
- d->compiled = (glGetError() == GL_NO_ERROR);
- otherShader.d->compiled = d->compiled;
- return d->compiled;
-}
-
-/*!
- Returns a list of all binary formats that are supported by
- setShaderBinary() on this system.
-
- \sa setShaderBinary()
-*/
-QList<GLenum> QGLShader::shaderBinaryFormats()
-{
- GLint num;
- QList<GLenum> list;
- glGetError(); // Clear error state.
- glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &num);
- if (glGetError() != GL_NO_ERROR || num <= 0)
- return list;
- QVarLengthArray<GLint> formats(num);
- glGetIntegerv(GL_SHADER_BINARY_FORMATS, formats.data());
- for (GLint i = 0; i < num; ++i)
- list += (GLenum)(formats[i]);
- return list;
+ return compileSourceCode(contents.constData());
}
/*!
Returns the source code for this shader.
- \sa compile()
+ \sa compileSourceCode()
*/
QByteArray QGLShader::sourceCode() const
{
- if (d->isPartial)
- return d->partialSource;
- if (!d->shader)
+ Q_D(const QGLShader);
+ GLuint shader = d->shaderGuard.id();
+ if (!shader)
return QByteArray();
GLint size = 0;
- glGetShaderiv(d->shader, GL_SHADER_SOURCE_LENGTH, &size);
+ glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &size);
if (size <= 0)
return QByteArray();
GLint len = 0;
char *source = new char [size];
- glGetShaderSource(d->shader, size, &len, source);
+ glGetShaderSource(shader, size, &len, source);
QByteArray src(source);
delete [] source;
return src;
@@ -689,73 +466,86 @@ QByteArray QGLShader::sourceCode() const
/*!
Returns true if this shader has been compiled; false otherwise.
- \sa compile()
+ \sa compileSourceCode(), compileSourceFile()
*/
bool QGLShader::isCompiled() const
{
+ Q_D(const QGLShader);
return d->compiled;
}
/*!
Returns the errors and warnings that occurred during the last compile.
- \sa compile()
+ \sa compileSourceCode(), compileSourceFile()
*/
QString QGLShader::log() const
{
+ Q_D(const QGLShader);
return d->log;
}
/*!
Returns the OpenGL identifier associated with this shader.
- If shaderType() is PartialVertexShader or PartialFragmentShader,
- this function will always return zero. Partial shaders are
- created and compiled when QGLShaderProgram::link() is called.
-
\sa QGLShaderProgram::programId()
*/
GLuint QGLShader::shaderId() const
{
- return d->shader;
+ Q_D(const QGLShader);
+ return d->shaderGuard.id();
}
#undef ctx
-#define ctx context
+#define ctx programGuard.context()
-class QGLShaderProgramPrivate
+class QGLShaderProgramPrivate : public QObjectPrivate
{
+ Q_DECLARE_PUBLIC(QGLShaderProgram)
public:
- QGLShaderProgramPrivate(const QGLContext *ctx)
- : context(ctx)
- , program(0)
+ QGLShaderProgramPrivate(const QGLContext *context)
+ : programGuard(context)
, linked(false)
, inited(false)
- , hasPartialShaders(false)
+ , removingShaders(false)
, vertexShader(0)
, fragmentShader(0)
{
}
- ~QGLShaderProgramPrivate()
- {
- if (program)
- glDeleteProgram(program);
- }
+ ~QGLShaderProgramPrivate();
- const QGLContext *context;
- GLuint program;
+ QGLSharedResourceGuard programGuard;
bool linked;
bool inited;
- bool hasPartialShaders;
+ bool removingShaders;
QString log;
QList<QGLShader *> shaders;
QList<QGLShader *> anonShaders;
QGLShader *vertexShader;
QGLShader *fragmentShader;
+
+ bool hasShader(QGLShader::ShaderType type) const;
};
+QGLShaderProgramPrivate::~QGLShaderProgramPrivate()
+{
+ if (programGuard.id()) {
+ QGLShareContextScope scope(programGuard.context());
+ glDeleteProgram(programGuard.id());
+ }
+}
+
+bool QGLShaderProgramPrivate::hasShader(QGLShader::ShaderType type) const
+{
+ foreach (QGLShader *shader, shaders) {
+ if (shader->shaderType() == type)
+ return true;
+ }
+ return false;
+}
+
#undef ctx
-#define ctx d->context
+#define ctx d->programGuard.context()
/*!
Constructs a new shader program and attaches it to \a parent.
@@ -766,9 +556,8 @@ public:
\sa addShader()
*/
QGLShaderProgram::QGLShaderProgram(QObject *parent)
- : QObject(parent)
+ : QObject(*new QGLShaderProgramPrivate(QGLContext::currentContext()), parent)
{
- d = new QGLShaderProgramPrivate(QGLContext::currentContext());
}
/*!
@@ -780,9 +569,8 @@ QGLShaderProgram::QGLShaderProgram(QObject *parent)
\sa addShader()
*/
QGLShaderProgram::QGLShaderProgram(const QGLContext *context, QObject *parent)
- : QObject(parent)
+ : QObject(*new QGLShaderProgramPrivate(context), parent)
{
- d = new QGLShaderProgramPrivate(context);
}
/*!
@@ -790,24 +578,28 @@ QGLShaderProgram::QGLShaderProgram(const QGLContext *context, QObject *parent)
*/
QGLShaderProgram::~QGLShaderProgram()
{
- delete d;
}
bool QGLShaderProgram::init()
{
- if (d->program || d->inited)
+ Q_D(QGLShaderProgram);
+ if (d->programGuard.id() || d->inited)
return true;
d->inited = true;
- if (!d->context)
- d->context = QGLContext::currentContext();
- if (!d->context)
+ const QGLContext *context = d->programGuard.context();
+ if (!context) {
+ context = QGLContext::currentContext();
+ d->programGuard.setContext(context);
+ }
+ if (!context)
return false;
- if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(d->context))) {
- d->program = glCreateProgram();
- if (!(d->program)) {
+ if (qt_resolve_glsl_extensions(const_cast<QGLContext *>(context))) {
+ GLuint program = glCreateProgram();
+ if (!program) {
qWarning() << "QGLShaderProgram: could not create shader program";
return false;
}
+ d->programGuard.setId(program);
return true;
} else {
qWarning() << "QGLShaderProgram: shader programs are not supported";
@@ -824,26 +616,30 @@ bool QGLShaderProgram::init()
is deleted. This allows the caller to add the same shader
to multiple shader programs.
+ \sa addShaderFromSourceCode(), addShaderFromSourceFile()
\sa removeShader(), link(), removeAllShaders()
*/
bool QGLShaderProgram::addShader(QGLShader *shader)
{
+ Q_D(QGLShaderProgram);
if (!init())
return false;
if (d->shaders.contains(shader))
return true; // Already added to this shader program.
- if (d->program && shader) {
- if (!shader->d->compiled)
+ if (d->programGuard.id() && shader) {
+ if (!QGLContext::areSharing(shader->d_func()->shaderGuard.context(),
+ d->programGuard.context())) {
+ qWarning("QGLShaderProgram::addShader: Program and shader are not associated with same context.");
return false;
- if (!shader->d->isPartial) {
- if (!shader->d->shader)
- return false;
- glAttachShader(d->program, shader->d->shader);
- } else {
- d->hasPartialShaders = true;
}
+ if (!shader->d_func()->compiled)
+ return false;
+ if (!shader->d_func()->shaderGuard.id())
+ return false;
+ 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;
@@ -860,14 +656,16 @@ bool QGLShaderProgram::addShader(QGLShader *shader)
adding vertex and fragment shaders to a shader program without
creating an instance of QGLShader first.
+ \sa addShader(), addShaderFromSourceFile()
\sa removeShader(), link(), log(), removeAllShaders()
*/
-bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const char *source)
+bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const char *source)
{
+ Q_D(QGLShaderProgram);
if (!init())
return false;
QGLShader *shader = new QGLShader(type, this);
- if (!shader->compile(source)) {
+ if (!shader->compileSourceCode(source)) {
d->log = shader->log();
delete shader;
return false;
@@ -888,11 +686,12 @@ bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const char *source)
adding vertex and fragment shaders to a shader program without
creating an instance of QGLShader first.
+ \sa addShader(), addShaderFromSourceFile()
\sa removeShader(), link(), log(), removeAllShaders()
*/
-bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QByteArray& source)
+bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const QByteArray& source)
{
- return addShader(type, source.constData());
+ return addShaderFromSourceCode(type, source.constData());
}
/*!
@@ -907,11 +706,40 @@ bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QByteArray& s
adding vertex and fragment shaders to a shader program without
creating an instance of QGLShader first.
+ \sa addShader(), addShaderFromSourceFile()
\sa removeShader(), link(), log(), removeAllShaders()
*/
-bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QString& source)
+bool QGLShaderProgram::addShaderFromSourceCode(QGLShader::ShaderType type, const QString& source)
{
- return addShader(type, source.toLatin1().constData());
+ 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 QGLShader first.
+
+ \sa addShader(), addShaderFromSourceCode()
+*/
+bool QGLShaderProgram::addShaderFromSourceFile
+ (QGLShader::ShaderType type, const QString& fileName)
+{
+ Q_D(QGLShaderProgram);
+ if (!init())
+ return false;
+ QGLShader *shader = new QGLShader(type, this);
+ if (!shader->compileSourceFile(fileName)) {
+ d->log = shader->log();
+ delete shader;
+ return false;
+ }
+ d->anonShaders.append(shader);
+ return addShader(shader);
}
/*!
@@ -921,12 +749,17 @@ bool QGLShaderProgram::addShader(QGLShader::ShaderType type, const QString& sour
*/
void QGLShaderProgram::removeShader(QGLShader *shader)
{
- if (d->program && shader && shader->d->shader) {
- glDetachShader(d->program, shader->d->shader);
- d->linked = false; // Program needs to be relinked.
+ Q_D(QGLShaderProgram);
+ if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id()) {
+ QGLShareContextScope scope(d->programGuard.context());
+ 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()));
}
- d->shaders.removeAll(shader);
- d->anonShaders.removeAll(shader);
}
/*!
@@ -937,6 +770,7 @@ void QGLShaderProgram::removeShader(QGLShader *shader)
*/
QList<QGLShader *> QGLShaderProgram::shaders() const
{
+ Q_D(const QGLShaderProgram);
return d->shaders;
}
@@ -950,9 +784,11 @@ QList<QGLShader *> QGLShaderProgram::shaders() const
*/
void QGLShaderProgram::removeAllShaders()
{
+ Q_D(QGLShaderProgram);
+ d->removingShaders = true;
foreach (QGLShader *shader, d->shaders) {
- if (d->program && shader && shader->d->shader)
- glDetachShader(d->program, shader->d->shader);
+ if (d->programGuard.id() && shader && shader->d_func()->shaderGuard.id())
+ glDetachShader(d->programGuard.id(), shader->d_func()->shaderGuard.id());
}
foreach (QGLShader *shader, d->anonShaders) {
// Delete shader objects that were created anonymously.
@@ -961,124 +797,7 @@ void QGLShaderProgram::removeAllShaders()
d->shaders.clear();
d->anonShaders.clear();
d->linked = false; // Program needs to be relinked.
-}
-
-#if defined(QT_OPENGL_ES_2)
-
-#ifndef GL_PROGRAM_BINARY_LENGTH_OES
-#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
-#endif
-#ifndef GL_NUM_PROGRAM_BINARY_FORMATS_OES
-#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE
-#endif
-#ifndef GL_PROGRAM_BINARY_FORMATS_OES
-#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF
-#endif
-
-#endif
-
-/*!
- Returns the program binary associated with this shader program.
- The numeric identifier of the program binary format is returned
- in \a format. The \c OES_get_program_binary extension will need
- to be supported by the system for binary retrieval to succeed.
-
- Returns an empty QByteArray if the program binary cannot be
- retrieved on this system, or the shader program has not yet
- been linked.
-
- The returned binary can be supplied to setProgramBinary() on the
- same machine at some future point to reload the program. It contains
- the compiled code of all of the shaders that were attached to the
- program at the time programBinary() is called.
-
- \sa setProgramBinary(), programBinaryFormats()
-*/
-QByteArray QGLShaderProgram::programBinary(int *format) const
-{
-#if defined(QT_OPENGL_ES_2)
- if (!isLinked())
- return QByteArray();
-
- // Get the length of the binary data, bailing out if there is none.
- GLint length = 0;
- glGetProgramiv(d->program, GL_PROGRAM_BINARY_LENGTH_OES, &length);
- if (length <= 0)
- return QByteArray();
-
- // Retrieve the binary data.
- QByteArray binary(length, 0);
- GLenum binaryFormat;
- glGetProgramBinaryOES(d->program, length, 0, &binaryFormat, binary.data());
- if (format)
- *format = (int)binaryFormat;
- return binary;
-#else
- Q_UNUSED(format);
- return QByteArray();
-#endif
-}
-
-/*!
- Sets the \a binary for this shader program according to \a format.
- Returns true if the binary was set, or false if the binary format
- is not supported or this system does not support program binaries.
- The program will be linked if the load succeeds.
-
- \sa programBinary(), programBinaryFormats(), isLinked()
-*/
-bool QGLShaderProgram::setProgramBinary(int format, const QByteArray& binary)
-{
-#if defined(QT_OPENGL_ES_2)
- // Load the binary and check that it was linked correctly.
- glProgramBinaryOES(d->program, (GLenum)format,
- binary.constData(), binary.size());
- GLint value = 0;
- glGetProgramiv(d->program, GL_LINK_STATUS, &value);
- d->linked = (value != 0);
- value = 0;
- glGetProgramiv(d->program, GL_INFO_LOG_LENGTH, &value);
- d->log = QString();
- if (value > 1) {
- char *logbuf = new char [value];
- GLint len;
- glGetProgramInfoLog(d->program, value, &len, logbuf);
- d->log = QString::fromLatin1(logbuf);
- QString name = objectName();
- if (name.isEmpty())
- qWarning() << "QGLShader::setProgramBinary:" << d->log;
- else
- qWarning() << "QGLShader::setProgramBinary[" << name << "]:" << d->log;
- delete [] logbuf;
- }
- return d->linked;
-#else
- Q_UNUSED(format);
- Q_UNUSED(binary);
- return false;
-#endif
-}
-
-/*!
- Returns the list of program binary formats that are accepted by
- this system for use with setProgramBinary().
-
- \sa programBinary(), setProgramBinary()
-*/
-QList<int> QGLShaderProgram::programBinaryFormats()
-{
-#if defined(QT_OPENGL_ES_2)
- GLint count = 0;
- glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS_OES, &count);
- if (count <= 0)
- return QList<int>();
- QVector<int> list;
- list.resize(count);
- glGetIntegerv(GL_PROGRAM_BINARY_FORMATS_OES, list.data());
- return list.toList();
-#else
- return QList<int>();
-#endif
+ d->removingShaders = false;
}
/*!
@@ -1097,64 +816,21 @@ QList<int> QGLShaderProgram::programBinaryFormats()
*/
bool QGLShaderProgram::link()
{
- if (!d->program)
+ Q_D(QGLShaderProgram);
+ GLuint program = d->programGuard.id();
+ if (!program)
return false;
- if (d->hasPartialShaders) {
- // Compile the partial vertex and fragment shaders.
- QByteArray vertexSource;
- QByteArray fragmentSource;
- foreach (QGLShader *shader, d->shaders) {
- if (shader->shaderType() == QGLShader::PartialVertexShader)
- vertexSource += shader->sourceCode();
- else if (shader->shaderType() == QGLShader::PartialFragmentShader)
- fragmentSource += shader->sourceCode();
- }
- if (vertexSource.isEmpty()) {
- if (d->vertexShader) {
- glDetachShader(d->program, d->vertexShader->d->shader);
- delete d->vertexShader;
- d->vertexShader = 0;
- }
- } else {
- if (!d->vertexShader) {
- d->vertexShader =
- new QGLShader(QGLShader::VertexShader, this);
- }
- if (!d->vertexShader->compile(vertexSource)) {
- d->log = d->vertexShader->log();
- return false;
- }
- glAttachShader(d->program, d->vertexShader->d->shader);
- }
- if (fragmentSource.isEmpty()) {
- if (d->fragmentShader) {
- glDetachShader(d->program, d->fragmentShader->d->shader);
- delete d->fragmentShader;
- d->fragmentShader = 0;
- }
- } else {
- if (!d->fragmentShader) {
- d->fragmentShader =
- new QGLShader(QGLShader::FragmentShader, this);
- }
- if (!d->fragmentShader->compile(fragmentSource)) {
- d->log = d->fragmentShader->log();
- return false;
- }
- glAttachShader(d->program, d->fragmentShader->d->shader);
- }
- }
- glLinkProgram(d->program);
+ glLinkProgram(program);
GLint value = 0;
- glGetProgramiv(d->program, GL_LINK_STATUS, &value);
+ glGetProgramiv(program, GL_LINK_STATUS, &value);
d->linked = (value != 0);
value = 0;
- glGetProgramiv(d->program, GL_INFO_LOG_LENGTH, &value);
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value);
d->log = QString();
if (value > 1) {
char *logbuf = new char [value];
GLint len;
- glGetProgramInfoLog(d->program, value, &len, logbuf);
+ glGetProgramInfoLog(program, value, &len, logbuf);
d->log = QString::fromLatin1(logbuf);
QString name = objectName();
if (name.isEmpty())
@@ -1173,6 +849,7 @@ bool QGLShaderProgram::link()
*/
bool QGLShaderProgram::isLinked() const
{
+ Q_D(const QGLShaderProgram);
return d->linked;
}
@@ -1184,24 +861,35 @@ bool QGLShaderProgram::isLinked() const
*/
QString QGLShaderProgram::log() const
{
+ Q_D(const QGLShaderProgram);
return d->log;
}
/*!
- Enable use of this shader program in the currently active QGLContext.
- Returns true if the program was successfully enabled; false
- otherwise. If the shader program has not yet been linked,
+ Binds this shader program to the active QGLContext 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(), disable()
+ \sa link(), release()
*/
-bool QGLShaderProgram::enable()
+bool QGLShaderProgram::bind()
{
- if (!d->program)
+ Q_D(QGLShaderProgram);
+ GLuint program = d->programGuard.id();
+ if (!program)
return false;
if (!d->linked && !link())
return false;
- glUseProgram(d->program);
+#ifndef QT_NO_DEBUG
+ if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext())) {
+ qWarning("QGLShaderProgram::bind: program is not valid in the current context.");
+ return false;
+ }
+#endif
+ glUseProgram(program);
return true;
}
@@ -1209,13 +897,18 @@ bool QGLShaderProgram::enable()
#define ctx QGLContext::currentContext()
/*!
- Disables the active shader program in the current QGLContext.
+ Releases the active shader program from the current QGLContext.
This is equivalent to calling \c{glUseProgram(0)}.
- \sa enable()
+ \sa bind()
*/
-void QGLShaderProgram::disable()
+void QGLShaderProgram::release()
{
+#ifndef QT_NO_DEBUG
+ Q_D(QGLShaderProgram);
+ if (!QGLContext::areSharing(d->programGuard.context(), QGLContext::currentContext()))
+ qWarning("QGLShaderProgram::release: program is not valid in the current context.");
+#endif
#if defined(QT_OPENGL_ES_2)
glUseProgram(0);
#else
@@ -1225,7 +918,7 @@ void QGLShaderProgram::disable()
}
#undef ctx
-#define ctx d->context
+#define ctx d->programGuard.context()
/*!
Returns the OpenGL identifier associated with this shader program.
@@ -1234,7 +927,8 @@ void QGLShaderProgram::disable()
*/
GLuint QGLShaderProgram::programId() const
{
- return d->program;
+ Q_D(const QGLShaderProgram);
+ return d->programGuard.id();
}
/*!
@@ -1247,7 +941,13 @@ GLuint QGLShaderProgram::programId() const
*/
void QGLShaderProgram::bindAttributeLocation(const char *name, int location)
{
- glBindAttribLocation(d->program, location, name);
+ Q_D(QGLShaderProgram);
+ if (!d->linked) {
+ glBindAttribLocation(d->programGuard.id(), location, name);
+ } else {
+ qWarning() << "QGLShaderProgram::bindAttributeLocation(" << name
+ << "): cannot bind after shader program is linked";
+ }
}
/*!
@@ -1262,7 +962,7 @@ void QGLShaderProgram::bindAttributeLocation(const char *name, int location)
*/
void QGLShaderProgram::bindAttributeLocation(const QByteArray& name, int location)
{
- glBindAttribLocation(d->program, location, name.constData());
+ bindAttributeLocation(name.constData(), location);
}
/*!
@@ -1277,7 +977,7 @@ void QGLShaderProgram::bindAttributeLocation(const QByteArray& name, int locatio
*/
void QGLShaderProgram::bindAttributeLocation(const QString& name, int location)
{
- glBindAttribLocation(d->program, location, name.toLatin1().constData());
+ bindAttributeLocation(name.toLatin1().constData(), location);
}
/*!
@@ -1289,8 +989,9 @@ void QGLShaderProgram::bindAttributeLocation(const QString& name, int location)
*/
int QGLShaderProgram::attributeLocation(const char *name) const
{
+ Q_D(const QGLShaderProgram);
if (d->linked) {
- return glGetAttribLocation(d->program, name);
+ return glGetAttribLocation(d->programGuard.id(), name);
} else {
qWarning() << "QGLShaderProgram::attributeLocation(" << name
<< "): shader program is not linked";
@@ -1333,6 +1034,8 @@ int QGLShaderProgram::attributeLocation(const QString& name) const
*/
void QGLShaderProgram::setAttributeValue(int location, GLfloat value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glVertexAttrib1fv(location, &value);
}
@@ -1357,6 +1060,8 @@ void QGLShaderProgram::setAttributeValue(const char *name, GLfloat value)
*/
void QGLShaderProgram::setAttributeValue(int location, GLfloat x, GLfloat y)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[2] = {x, y};
glVertexAttrib2fv(location, values);
@@ -1385,6 +1090,8 @@ void QGLShaderProgram::setAttributeValue(const char *name, GLfloat x, GLfloat y)
void QGLShaderProgram::setAttributeValue
(int location, GLfloat x, GLfloat y, GLfloat z)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[3] = {x, y, z};
glVertexAttrib3fv(location, values);
@@ -1414,6 +1121,8 @@ void QGLShaderProgram::setAttributeValue
void QGLShaderProgram::setAttributeValue
(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {x, y, z, w};
glVertexAttrib4fv(location, values);
@@ -1441,6 +1150,8 @@ void QGLShaderProgram::setAttributeValue
*/
void QGLShaderProgram::setAttributeValue(int location, const QVector2D& value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glVertexAttrib2fv(location, reinterpret_cast<const GLfloat *>(&value));
}
@@ -1464,6 +1175,8 @@ void QGLShaderProgram::setAttributeValue(const char *name, const QVector2D& valu
*/
void QGLShaderProgram::setAttributeValue(int location, const QVector3D& value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glVertexAttrib3fv(location, reinterpret_cast<const GLfloat *>(&value));
}
@@ -1487,6 +1200,8 @@ void QGLShaderProgram::setAttributeValue(const char *name, const QVector3D& valu
*/
void QGLShaderProgram::setAttributeValue(int location, const QVector4D& value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glVertexAttrib4fv(location, reinterpret_cast<const GLfloat *>(&value));
}
@@ -1510,6 +1225,8 @@ void QGLShaderProgram::setAttributeValue(const char *name, const QVector4D& valu
*/
void QGLShaderProgram::setAttributeValue(int location, const QColor& value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {value.redF(), value.greenF(), value.blueF(), value.alphaF()};
glVertexAttrib4fv(location, values);
@@ -1540,6 +1257,8 @@ void QGLShaderProgram::setAttributeValue(const char *name, const QColor& value)
void QGLShaderProgram::setAttributeValue
(int location, const GLfloat *values, int columns, int rows)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (rows < 1 || rows > 4) {
qWarning() << "QGLShaderProgram::setAttributeValue: rows" << rows << "not supported";
return;
@@ -1579,20 +1298,26 @@ void QGLShaderProgram::setAttributeValue
/*!
Sets an array of vertex \a values on the attribute at \a location
- in this shader program. The \a size indicates the number of
+ 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.
- \sa setAttributeValue(), setUniformValue(), disableAttributeArray()
+ 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 QGLShaderProgram::setAttributeArray
- (int location, const GLfloat *values, int size, int stride)
+ (int location, const GLfloat *values, int tupleSize, int stride)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
- glVertexAttribPointer(location, size, GL_FLOAT, GL_FALSE,
+ glVertexAttribPointer(location, tupleSize, GL_FLOAT, GL_FALSE,
stride, values);
- glEnableVertexAttribArray(location);
}
}
@@ -1602,15 +1327,21 @@ void QGLShaderProgram::setAttributeArray
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
- \sa setAttributeValue(), setUniformValue(), disableAttributeArray()
+ 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 QGLShaderProgram::setAttributeArray
(int location, const QVector2D *values, int stride)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE,
stride, values);
- glEnableVertexAttribArray(location);
}
}
@@ -1620,15 +1351,21 @@ void QGLShaderProgram::setAttributeArray
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
- \sa setAttributeValue(), setUniformValue(), disableAttributeArray()
+ 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 QGLShaderProgram::setAttributeArray
(int location, const QVector3D *values, int stride)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE,
stride, values);
- glEnableVertexAttribArray(location);
}
}
@@ -1638,15 +1375,21 @@ void QGLShaderProgram::setAttributeArray
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
- \sa setAttributeValue(), setUniformValue(), disableAttributeArray()
+ 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 QGLShaderProgram::setAttributeArray
(int location, const QVector4D *values, int stride)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE,
stride, values);
- glEnableVertexAttribArray(location);
}
}
@@ -1654,17 +1397,22 @@ void QGLShaderProgram::setAttributeArray
\overload
Sets an array of vertex \a values on the attribute called \a name
- in this shader program. The \a size indicates the number of
+ 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.
- \sa setAttributeValue(), setUniformValue(), disableAttributeArray()
+ 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 QGLShaderProgram::setAttributeArray
- (const char *name, const GLfloat *values, int size, int stride)
+ (const char *name, const GLfloat *values, int tupleSize, int stride)
{
- setAttributeArray(attributeLocation(name), values, size, stride);
+ setAttributeArray(attributeLocation(name), values, tupleSize, stride);
}
/*!
@@ -1675,7 +1423,12 @@ void QGLShaderProgram::setAttributeArray
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
- \sa setAttributeValue(), setUniformValue(), disableAttributeArray()
+ 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 QGLShaderProgram::setAttributeArray
(const char *name, const QVector2D *values, int stride)
@@ -1691,7 +1444,12 @@ void QGLShaderProgram::setAttributeArray
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
- \sa setAttributeValue(), setUniformValue(), disableAttributeArray()
+ 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 QGLShaderProgram::setAttributeArray
(const char *name, const QVector3D *values, int stride)
@@ -1707,7 +1465,12 @@ void QGLShaderProgram::setAttributeArray
between vertices. A default \a stride value of zero indicates that
the vertices are densely packed in \a values.
- \sa setAttributeValue(), setUniformValue(), disableAttributeArray()
+ 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 QGLShaderProgram::setAttributeArray
(const char *name, const QVector4D *values, int stride)
@@ -1716,13 +1479,47 @@ void QGLShaderProgram::setAttributeArray
}
/*!
+ 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 QGLShaderProgram::enableAttributeArray(int location)
+{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ if (location != -1)
+ 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 QGLShaderProgram::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 setAttributeArray().
+ that was enabled by a previous call to enableAttributeArray().
- \sa setAttributeArray(), setAttributeValue(), setUniformValue()
+ \sa enableAttributeArray(), setAttributeArray(), setAttributeValue()
+ \sa setUniformValue()
*/
void QGLShaderProgram::disableAttributeArray(int location)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glDisableVertexAttribArray(location);
}
@@ -1731,9 +1528,10 @@ void QGLShaderProgram::disableAttributeArray(int location)
\overload
Disables the vertex array called \a name in this shader program
- that was enabled by a previous call to setAttributeArray().
+ that was enabled by a previous call to enableAttributeArray().
- \sa setAttributeArray(), setAttributeValue(), setUniformValue()
+ \sa enableAttributeArray(), setAttributeArray(), setAttributeValue()
+ \sa setUniformValue()
*/
void QGLShaderProgram::disableAttributeArray(const char *name)
{
@@ -1749,8 +1547,10 @@ void QGLShaderProgram::disableAttributeArray(const char *name)
*/
int QGLShaderProgram::uniformLocation(const char *name) const
{
+ Q_D(const QGLShaderProgram);
+ Q_UNUSED(d);
if (d->linked) {
- return glGetUniformLocation(d->program, name);
+ return glGetUniformLocation(d->programGuard.id(), name);
} else {
qWarning() << "QGLShaderProgram::uniformLocation(" << name
<< "): shader program is not linked";
@@ -1793,6 +1593,8 @@ int QGLShaderProgram::uniformLocation(const QString& name) const
*/
void QGLShaderProgram::setUniformValue(int location, GLfloat value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform1fv(location, 1, &value);
}
@@ -1817,6 +1619,8 @@ void QGLShaderProgram::setUniformValue(const char *name, GLfloat value)
*/
void QGLShaderProgram::setUniformValue(int location, GLint value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform1i(location, value);
}
@@ -1842,6 +1646,8 @@ void QGLShaderProgram::setUniformValue(const char *name, GLint value)
*/
void QGLShaderProgram::setUniformValue(int location, GLuint value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform1i(location, value);
}
@@ -1867,6 +1673,8 @@ void QGLShaderProgram::setUniformValue(const char *name, GLuint value)
*/
void QGLShaderProgram::setUniformValue(int location, GLfloat x, GLfloat y)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[2] = {x, y};
glUniform2fv(location, 1, values);
@@ -1895,6 +1703,8 @@ void QGLShaderProgram::setUniformValue(const char *name, GLfloat x, GLfloat y)
void QGLShaderProgram::setUniformValue
(int location, GLfloat x, GLfloat y, GLfloat z)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[3] = {x, y, z};
glUniform3fv(location, 1, values);
@@ -1924,6 +1734,8 @@ void QGLShaderProgram::setUniformValue
void QGLShaderProgram::setUniformValue
(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {x, y, z, w};
glUniform4fv(location, 1, values);
@@ -1951,6 +1763,8 @@ void QGLShaderProgram::setUniformValue
*/
void QGLShaderProgram::setUniformValue(int location, const QVector2D& value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform2fv(location, 1, reinterpret_cast<const GLfloat *>(&value));
}
@@ -1975,6 +1789,8 @@ void QGLShaderProgram::setUniformValue(const char *name, const QVector2D& value)
*/
void QGLShaderProgram::setUniformValue(int location, const QVector3D& value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform3fv(location, 1, reinterpret_cast<const GLfloat *>(&value));
}
@@ -1999,6 +1815,8 @@ void QGLShaderProgram::setUniformValue(const char *name, const QVector3D& value)
*/
void QGLShaderProgram::setUniformValue(int location, const QVector4D& value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform4fv(location, 1, reinterpret_cast<const GLfloat *>(&value));
}
@@ -2024,6 +1842,8 @@ void QGLShaderProgram::setUniformValue(const char *name, const QVector4D& value)
*/
void QGLShaderProgram::setUniformValue(int location, const QColor& color)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {color.redF(), color.greenF(), color.blueF(), color.alphaF()};
glUniform4fv(location, 1, values);
@@ -2051,6 +1871,8 @@ void QGLShaderProgram::setUniformValue(const char *name, const QColor& color)
*/
void QGLShaderProgram::setUniformValue(int location, const QPoint& point)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {point.x(), point.y()};
glUniform2fv(location, 1, values);
@@ -2078,6 +1900,8 @@ void QGLShaderProgram::setUniformValue(const char *name, const QPoint& point)
*/
void QGLShaderProgram::setUniformValue(int location, const QPointF& point)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {point.x(), point.y()};
glUniform2fv(location, 1, values);
@@ -2105,6 +1929,8 @@ void QGLShaderProgram::setUniformValue(const char *name, const QPointF& point)
*/
void QGLShaderProgram::setUniformValue(int location, const QSize& size)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {size.width(), size.width()};
glUniform2fv(location, 1, values);
@@ -2132,6 +1958,8 @@ void QGLShaderProgram::setUniformValue(const char *name, const QSize& size)
*/
void QGLShaderProgram::setUniformValue(int location, const QSizeF& size)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat values[4] = {size.width(), size.height()};
glUniform2fv(location, 1, values);
@@ -2151,6 +1979,58 @@ void QGLShaderProgram::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<const GLfloat *>(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); \
+ }
+#if !defined(QT_OPENGL_ES_2)
+#define setUniformGenericMatrix(func,colfunc,location,value,cols,rows) \
+ if (location == -1) \
+ return; \
+ if (sizeof(qreal) == sizeof(GLfloat)) { \
+ const GLfloat *data = reinterpret_cast<const GLfloat *> \
+ (value.constData()); \
+ if (func) \
+ func(location, 1, GL_FALSE, data); \
+ else \
+ 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]; \
+ if (func) \
+ func(location, 1, GL_FALSE, mat); \
+ else \
+ colfunc(location, cols, mat); \
+ }
+#else
+#define setUniformGenericMatrix(func,colfunc,location,value,cols,rows) \
+ if (location == -1) \
+ return; \
+ if (sizeof(qreal) == sizeof(GLfloat)) { \
+ const GLfloat *data = reinterpret_cast<const GLfloat *> \
+ (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); \
+ }
+#endif
+
/*!
Sets the uniform variable at \a location in the current context
to a 2x2 matrix \a value.
@@ -2159,8 +2039,9 @@ void QGLShaderProgram::setUniformValue(const char *name, const QSizeF& size)
*/
void QGLShaderProgram::setUniformValue(int location, const QMatrix2x2& value)
{
- if (location != -1)
- glUniformMatrix2fv(location, 1, GL_FALSE, value.data());
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformMatrix(glUniformMatrix2fv, location, value, 2, 2);
}
/*!
@@ -2184,20 +2065,10 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x2& value
*/
void QGLShaderProgram::setUniformValue(int location, const QMatrix2x3& value)
{
-#if !defined(QT_OPENGL_ES_2)
- if (location != -1) {
- if (glUniformMatrix2x3fv) {
- // OpenGL 2.1+: pass the matrix directly.
- glUniformMatrix2x3fv(location, 1, GL_FALSE, value.data());
- } else {
- // OpenGL 2.0: pass the matrix columns as a vector.
- glUniform3fv(location, 2, value.data());
- }
- }
-#else
- if (location != -1)
- glUniform3fv(location, 2, value.data());
-#endif
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix2x3fv, glUniform3fv, location, value, 2, 3);
}
/*!
@@ -2221,20 +2092,10 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x3& value
*/
void QGLShaderProgram::setUniformValue(int location, const QMatrix2x4& value)
{
-#if !defined(QT_OPENGL_ES_2)
- if (location != -1) {
- if (glUniformMatrix2x4fv) {
- // OpenGL 2.1+: pass the matrix directly.
- glUniformMatrix2x4fv(location, 1, GL_FALSE, value.data());
- } else {
- // OpenGL 2.0: pass the matrix columns as a vector.
- glUniform4fv(location, 2, value.data());
- }
- }
-#else
- if (location != -1)
- glUniform4fv(location, 2, value.data());
-#endif
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix2x4fv, glUniform4fv, location, value, 2, 4);
}
/*!
@@ -2258,20 +2119,10 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix2x4& value
*/
void QGLShaderProgram::setUniformValue(int location, const QMatrix3x2& value)
{
-#if !defined(QT_OPENGL_ES_2)
- if (location != -1) {
- if (glUniformMatrix3x2fv) {
- // OpenGL 2.1+: pass the matrix directly.
- glUniformMatrix3x2fv(location, 1, GL_FALSE, value.data());
- } else {
- // OpenGL 2.0: pass the matrix columns as a vector.
- glUniform2fv(location, 3, value.data());
- }
- }
-#else
- if (location != -1)
- glUniform2fv(location, 3, value.data());
-#endif
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix3x2fv, glUniform2fv, location, value, 3, 2);
}
/*!
@@ -2295,8 +2146,9 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x2& value
*/
void QGLShaderProgram::setUniformValue(int location, const QMatrix3x3& value)
{
- if (location != -1)
- glUniformMatrix3fv(location, 1, GL_FALSE, value.data());
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformMatrix(glUniformMatrix3fv, location, value, 3, 3);
}
/*!
@@ -2320,20 +2172,10 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x3& value
*/
void QGLShaderProgram::setUniformValue(int location, const QMatrix3x4& value)
{
-#if !defined(QT_OPENGL_ES_2)
- if (location != -1) {
- if (glUniformMatrix3x4fv) {
- // OpenGL 2.1+: pass the matrix directly.
- glUniformMatrix3x4fv(location, 1, GL_FALSE, value.data());
- } else {
- // OpenGL 2.0: pass the matrix columns as a vector.
- glUniform4fv(location, 3, value.data());
- }
- }
-#else
- if (location != -1)
- glUniform4fv(location, 3, value.data());
-#endif
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix3x4fv, glUniform4fv, location, value, 3, 4);
}
/*!
@@ -2357,20 +2199,10 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix3x4& value
*/
void QGLShaderProgram::setUniformValue(int location, const QMatrix4x2& value)
{
-#if !defined(QT_OPENGL_ES_2)
- if (location != -1) {
- if (glUniformMatrix4x2fv) {
- // OpenGL 2.1+: pass the matrix directly.
- glUniformMatrix4x2fv(location, 1, GL_FALSE, value.data());
- } else {
- // OpenGL 2.0: pass the matrix columns as a vector.
- glUniform2fv(location, 4, value.data());
- }
- }
-#else
- if (location != -1)
- glUniform2fv(location, 4, value.data());
-#endif
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix4x2fv, glUniform2fv, location, value, 4, 2);
}
/*!
@@ -2394,20 +2226,10 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x2& value
*/
void QGLShaderProgram::setUniformValue(int location, const QMatrix4x3& value)
{
-#if !defined(QT_OPENGL_ES_2)
- if (location != -1) {
- if (glUniformMatrix4x3fv) {
- // OpenGL 2.1+: pass the matrix directly.
- glUniformMatrix4x3fv(location, 1, GL_FALSE, value.data());
- } else {
- // OpenGL 2.0: pass the matrix columns as a vector.
- glUniform3fv(location, 4, value.data());
- }
- }
-#else
- if (location != -1)
- glUniform3fv(location, 4, value.data());
-#endif
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformGenericMatrix
+ (glUniformMatrix4x3fv, glUniform3fv, location, value, 4, 3);
}
/*!
@@ -2431,8 +2253,9 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x3& value
*/
void QGLShaderProgram::setUniformValue(int location, const QMatrix4x4& value)
{
- if (location != -1)
- glUniformMatrix4fv(location, 1, GL_FALSE, value.data());
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
+ setUniformMatrix(glUniformMatrix4fv, location, value, 4, 4);
}
/*!
@@ -2459,6 +2282,8 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x4& value
*/
void QGLShaderProgram::setUniformValue(int location, const GLfloat value[4][4])
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniformMatrix4fv(location, 1, GL_FALSE, value[0]);
}
@@ -2486,6 +2311,8 @@ void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[4][
*/
void QGLShaderProgram::setUniformValue(int location, const QTransform& value)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
GLfloat mat[3][3] = {
{value.m11(), value.m12(), value.m13()},
@@ -2519,6 +2346,8 @@ void QGLShaderProgram::setUniformValue
*/
void QGLShaderProgram::setUniformValueArray(int location, const GLint *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform1iv(location, count, values);
}
@@ -2546,6 +2375,8 @@ void QGLShaderProgram::setUniformValueArray
*/
void QGLShaderProgram::setUniformValueArray(int location, const GLuint *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform1iv(location, count, reinterpret_cast<const GLint *>(values));
}
@@ -2568,23 +2399,25 @@ void QGLShaderProgram::setUniformValueArray
/*!
Sets the uniform variable array at \a location in the current
context to the \a count elements of \a values. Each element
- has \a size components. The \a size must be 1, 2, 3, or 4.
+ has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4.
\sa setAttributeValue()
*/
-void QGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int size)
+void QGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1) {
- if (size == 1)
+ if (tupleSize == 1)
glUniform1fv(location, count, values);
- else if (size == 2)
+ else if (tupleSize == 2)
glUniform2fv(location, count, values);
- else if (size == 3)
+ else if (tupleSize == 3)
glUniform3fv(location, count, values);
- else if (size == 4)
+ else if (tupleSize == 4)
glUniform4fv(location, count, values);
else
- qWarning() << "QGLShaderProgram::setUniformValue: size" << size << "not supported";
+ qWarning() << "QGLShaderProgram::setUniformValue: size" << tupleSize << "not supported";
}
}
@@ -2593,14 +2426,14 @@ void QGLShaderProgram::setUniformValueArray(int location, const GLfloat *values,
Sets the uniform variable array called \a name in the current
context to the \a count elements of \a values. Each element
- has \a size components. The \a size must be 1, 2, 3, or 4.
+ has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4.
\sa setAttributeValue()
*/
void QGLShaderProgram::setUniformValueArray
- (const char *name, const GLfloat *values, int count, int size)
+ (const char *name, const GLfloat *values, int count, int tupleSize)
{
- setUniformValueArray(uniformLocation(name), values, count, size);
+ setUniformValueArray(uniformLocation(name), values, count, tupleSize);
}
/*!
@@ -2611,6 +2444,8 @@ void QGLShaderProgram::setUniformValueArray
*/
void QGLShaderProgram::setUniformValueArray(int location, const QVector2D *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform2fv(location, count, reinterpret_cast<const GLfloat *>(values));
}
@@ -2636,6 +2471,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QVector2D *v
*/
void QGLShaderProgram::setUniformValueArray(int location, const QVector3D *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform3fv(location, count, reinterpret_cast<const GLfloat *>(values));
}
@@ -2661,6 +2498,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QVector3D *v
*/
void QGLShaderProgram::setUniformValueArray(int location, const QVector4D *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
if (location != -1)
glUniform4fv(location, count, reinterpret_cast<const GLfloat *>(values));
}
@@ -2678,18 +2517,20 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *v
setUniformValueArray(uniformLocation(name), values, count);
}
-// We may have to repack matrix arrays if the matrix types
-// contain additional flag bits. Especially QMatrix4x4.
+// 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 (count == 1 || sizeof(type) == cols * rows * sizeof(GLfloat)) { \
- func(location, count, GL_FALSE, values->constData()); \
+ if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \
+ func(location, count, GL_FALSE, \
+ reinterpret_cast<const GLfloat *>(values[0].constData())); \
} else { \
QVarLengthArray<GLfloat> temp(cols * rows * count); \
for (int index = 0; index < count; ++index) { \
- qMemCopy(temp.data() + cols * rows * index, \
- values[index].constData(), cols * rows * sizeof(GLfloat)); \
+ 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()); \
}
@@ -2697,16 +2538,20 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *v
#define setUniformGenericMatrixArray(func,colfunc,location,values,count,type,cols,rows) \
if (location == -1 || count <= 0) \
return; \
- if (count == 1 || sizeof(type) == cols * rows * sizeof(GLfloat)) { \
+ if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \
+ const GLfloat *data = reinterpret_cast<const GLfloat *> \
+ (values[0].constData()); \
if (func) \
- func(location, count, GL_FALSE, values->constData()); \
+ func(location, count, GL_FALSE, data); \
else \
- colfunc(location, cols * count, values->constData()); \
+ colfunc(location, count * cols, data); \
} else { \
QVarLengthArray<GLfloat> temp(cols * rows * count); \
for (int index = 0; index < count; ++index) { \
- qMemCopy(temp.data() + cols * rows * index, \
- values[index].constData(), cols * rows * sizeof(GLfloat)); \
+ for (int index2 = 0; index2 < (cols * rows); ++index2) { \
+ temp.data()[cols * rows * index + index2] = \
+ values[index].constData()[index2]; \
+ } \
} \
if (func) \
func(location, count, GL_FALSE, temp.constData()); \
@@ -2717,13 +2562,17 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *v
#define setUniformGenericMatrixArray(func,colfunc,location,values,count,type,cols,rows) \
if (location == -1 || count <= 0) \
return; \
- if (count == 1 || sizeof(type) == cols * rows * sizeof(GLfloat)) { \
- colfunc(location, cols * count, values->constData()); \
+ if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \
+ const GLfloat *data = reinterpret_cast<const GLfloat *> \
+ (values[0].constData()); \
+ colfunc(location, count * cols, data); \
} else { \
QVarLengthArray<GLfloat> temp(cols * rows * count); \
for (int index = 0; index < count; ++index) { \
- qMemCopy(temp.data() + cols * rows * index, \
- values[index].constData(), cols * rows * sizeof(GLfloat)); \
+ for (int index2 = 0; index2 < (cols * rows); ++index2) { \
+ temp.data()[cols * rows * index + index2] = \
+ values[index].constData()[index2]; \
+ } \
} \
colfunc(location, count * cols, temp.constData()); \
}
@@ -2737,6 +2586,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *v
*/
void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x2 *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
setUniformMatrixArray
(glUniformMatrix2fv, location, values, count, QMatrix2x2, 2, 2);
}
@@ -2762,6 +2613,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x2 *
*/
void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x3 *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
setUniformGenericMatrixArray
(glUniformMatrix2x3fv, glUniform3fv, location, values, count,
QMatrix2x3, 2, 3);
@@ -2788,6 +2641,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x3 *
*/
void QGLShaderProgram::setUniformValueArray(int location, const QMatrix2x4 *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
setUniformGenericMatrixArray
(glUniformMatrix2x4fv, glUniform4fv, location, values, count,
QMatrix2x4, 2, 4);
@@ -2814,6 +2669,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x4 *
*/
void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x2 *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
setUniformGenericMatrixArray
(glUniformMatrix3x2fv, glUniform2fv, location, values, count,
QMatrix3x2, 3, 2);
@@ -2840,6 +2697,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x2 *
*/
void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x3 *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
setUniformMatrixArray
(glUniformMatrix3fv, location, values, count, QMatrix3x3, 3, 3);
}
@@ -2865,6 +2724,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x3 *
*/
void QGLShaderProgram::setUniformValueArray(int location, const QMatrix3x4 *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
setUniformGenericMatrixArray
(glUniformMatrix3x4fv, glUniform4fv, location, values, count,
QMatrix3x4, 3, 4);
@@ -2891,6 +2752,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x4 *
*/
void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x2 *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
setUniformGenericMatrixArray
(glUniformMatrix4x2fv, glUniform2fv, location, values, count,
QMatrix4x2, 4, 2);
@@ -2917,6 +2780,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x2 *
*/
void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x3 *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
setUniformGenericMatrixArray
(glUniformMatrix4x3fv, glUniform3fv, location, values, count,
QMatrix4x3, 4, 3);
@@ -2943,6 +2808,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x3 *
*/
void QGLShaderProgram::setUniformValueArray(int location, const QMatrix4x4 *values, int count)
{
+ Q_D(QGLShaderProgram);
+ Q_UNUSED(d);
setUniformMatrixArray
(glUniformMatrix4fv, location, values, count, QMatrix4x4, 4, 4);
}
@@ -2960,6 +2827,8 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 *
setUniformValueArray(uniformLocation(name), values, count);
}
+#undef ctx
+
/*!
Returns true if shader programs written in the OpenGL Shading
Language (GLSL) are supported on this system; false otherwise.
@@ -2967,7 +2836,7 @@ void QGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 *
The \a context is used to resolve the GLSL extensions.
If \a context is null, then QGLContext::currentContext() is used.
*/
-bool QGLShaderProgram::hasShaderPrograms(const QGLContext *context)
+bool QGLShaderProgram::hasOpenGLShaderPrograms(const QGLContext *context)
{
#if !defined(QT_OPENGL_ES_2)
if (!context)
@@ -2981,6 +2850,67 @@ bool QGLShaderProgram::hasShaderPrograms(const QGLContext *context)
#endif
}
+/*!
+ \internal
+*/
+void QGLShaderProgram::shaderDestroyed()
+{
+ Q_D(QGLShaderProgram);
+ QGLShader *shader = qobject_cast<QGLShader *>(sender());
+ if (shader && !d->removingShaders)
+ removeShader(shader);
+}
+
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+/*! \internal */
+void QGLShaderProgram::setUniformValue(int location, QMacCompatGLint value)
+{
+ setUniformValue(location, GLint(value));
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValue(int location, QMacCompatGLuint value)
+{
+ setUniformValue(location, GLuint(value));
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValue(const char *name, QMacCompatGLint value)
+{
+ setUniformValue(name, GLint(value));
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValue(const char *name, QMacCompatGLuint value)
+{
+ setUniformValue(name, GLuint(value));
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValueArray(int location, const QMacCompatGLint *values, int count)
+{
+ setUniformValueArray(location, (const GLint *)values, count);
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValueArray(int location, const QMacCompatGLuint *values, int count)
+{
+ setUniformValueArray(location, (const GLuint *)values, count);
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMacCompatGLint *values, int count)
+{
+ setUniformValueArray(name, (const GLint *)values, count);
+}
+
+/*! \internal */
+void QGLShaderProgram::setUniformValueArray(const char *name, const QMacCompatGLuint *values, int count)
+{
+ setUniformValueArray(name, (const GLuint *)values, count);
+}
#endif
+#endif // !defined(QT_OPENGL_ES_1_CL) && !defined(QT_OPENGL_ES_1)
+
QT_END_NAMESPACE
diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h
index c5295eb59..deeaee2bf 100644
--- a/src/opengl/qglshaderprogram.h
+++ b/src/opengl/qglshaderprogram.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -63,33 +63,23 @@ class Q_OPENGL_EXPORT QGLShader : public QObject
{
Q_OBJECT
public:
- enum ShaderType
+ enum ShaderTypeBit
{
- VertexShader,
- FragmentShader,
- PartialVertexShader,
- PartialFragmentShader
+ Vertex = 0x0001,
+ Fragment = 0x0002
};
+ Q_DECLARE_FLAGS(ShaderType, ShaderTypeBit)
explicit QGLShader(QGLShader::ShaderType type, QObject *parent = 0);
- explicit QGLShader(const QString& fileName, QObject *parent = 0);
- QGLShader(const QString& fileName, QGLShader::ShaderType type, QObject *parent = 0);
QGLShader(QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0);
- QGLShader(const QString& fileName, const QGLContext *context, QObject *parent = 0);
- QGLShader(const QString& fileName, QGLShader::ShaderType type, const QGLContext *context, QObject *parent = 0);
virtual ~QGLShader();
QGLShader::ShaderType shaderType() const;
- bool compile(const char *source);
- bool compile(const QByteArray& source);
- bool compile(const QString& source);
- bool compileFile(const QString& fileName);
-
- bool setShaderBinary(GLenum format, const void *binary, int length);
- bool setShaderBinary(QGLShader& otherShader, GLenum format, const void *binary, int length);
-
- static QList<GLenum> shaderBinaryFormats();
+ bool compileSourceCode(const char *source);
+ bool compileSourceCode(const QByteArray& source);
+ bool compileSourceCode(const QString& source);
+ bool compileSourceFile(const QString& fileName);
QByteArray sourceCode() const;
@@ -99,13 +89,15 @@ public:
GLuint shaderId() const;
private:
- QGLShaderPrivate *d;
-
friend class QGLShaderProgram;
Q_DISABLE_COPY(QGLShader)
+ Q_DECLARE_PRIVATE(QGLShader)
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QGLShader::ShaderType)
+
+
class QGLShaderProgramPrivate;
class Q_OPENGL_EXPORT QGLShaderProgram : public QObject
@@ -120,22 +112,19 @@ public:
void removeShader(QGLShader *shader);
QList<QGLShader *> shaders() const;
- bool addShader(QGLShader::ShaderType type, const char *source);
- bool addShader(QGLShader::ShaderType type, const QByteArray& source);
- bool addShader(QGLShader::ShaderType type, const QString& source);
+ bool addShaderFromSourceCode(QGLShader::ShaderType type, const char *source);
+ bool addShaderFromSourceCode(QGLShader::ShaderType type, const QByteArray& source);
+ bool addShaderFromSourceCode(QGLShader::ShaderType type, const QString& source);
+ bool addShaderFromSourceFile(QGLShader::ShaderType type, const QString& fileName);
void removeAllShaders();
- QByteArray programBinary(int *format) const;
- bool setProgramBinary(int format, const QByteArray& binary);
- static QList<int> programBinaryFormats();
-
virtual bool link();
bool isLinked() const;
QString log() const;
- bool enable();
- static void disable();
+ bool bind();
+ void release();
GLuint programId() const;
@@ -168,7 +157,7 @@ public:
void setAttributeValue(const char *name, const GLfloat *values, int columns, int rows);
void setAttributeArray
- (int location, const GLfloat *values, int size, int stride = 0);
+ (int location, const GLfloat *values, int tupleSize, int stride = 0);
void setAttributeArray
(int location, const QVector2D *values, int stride = 0);
void setAttributeArray
@@ -176,13 +165,16 @@ public:
void setAttributeArray
(int location, const QVector4D *values, int stride = 0);
void setAttributeArray
- (const char *name, const GLfloat *values, int size, int stride = 0);
+ (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 enableAttributeArray(int location);
+ void enableAttributeArray(const char *name);
void disableAttributeArray(int location);
void disableAttributeArray(const char *name);
@@ -190,6 +182,17 @@ public:
int uniformLocation(const QByteArray& name) const;
int uniformLocation(const QString& name) const;
+#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
+ void setUniformValue(int location, QMacCompatGLint value);
+ void setUniformValue(int location, QMacCompatGLuint value);
+ void setUniformValue(const char *name, QMacCompatGLint value);
+ void setUniformValue(const char *name, QMacCompatGLuint value);
+ void setUniformValueArray(int location, const QMacCompatGLint *values, int count);
+ void setUniformValueArray(int location, const QMacCompatGLuint *values, int count);
+ void setUniformValueArray(const char *name, const QMacCompatGLint *values, int count);
+ void setUniformValueArray(const char *name, const QMacCompatGLuint *values, int count);
+#endif
+
void setUniformValue(int location, GLfloat value);
void setUniformValue(int location, GLint value);
void setUniformValue(int location, GLuint value);
@@ -242,7 +245,7 @@ public:
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 size);
+ 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);
@@ -258,7 +261,7 @@ public:
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 size);
+ 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);
@@ -274,12 +277,14 @@ public:
void setUniformValueArray(const char *name, const QMatrix4x3 *values, int count);
void setUniformValueArray(const char *name, const QMatrix4x4 *values, int count);
- static bool hasShaderPrograms(const QGLContext *context = 0);
+ static bool hasOpenGLShaderPrograms(const QGLContext *context = 0);
-private:
- QGLShaderProgramPrivate *d;
+private Q_SLOTS:
+ void shaderDestroyed();
+private:
Q_DISABLE_COPY(QGLShaderProgram)
+ Q_DECLARE_PRIVATE(QGLShaderProgram)
bool init();
};
diff --git a/src/opengl/qglwindowsurface_qws.cpp b/src/opengl/qglwindowsurface_qws.cpp
index c54513638..5041cb9d9 100644
--- a/src/opengl/qglwindowsurface_qws.cpp
+++ b/src/opengl/qglwindowsurface_qws.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -43,7 +43,6 @@
#include <QtGui/QWidget>
#include <QtOpenGL/QGLWidget>
#include "private/qglwindowsurface_qws_p.h"
-#include "private/qglpaintdevice_qws_p.h"
#include "private/qpaintengine_opengl_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/opengl/qglwindowsurface_qws_p.h b/src/opengl/qglwindowsurface_qws_p.h
index d6c74611b..0c7682ae4 100644
--- a/src/opengl/qglwindowsurface_qws_p.h
+++ b/src/opengl/qglwindowsurface_qws_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/qgraphicsshadereffect.cpp b/src/opengl/qgraphicsshadereffect.cpp
new file mode 100644
index 000000000..4d7a69ce9
--- /dev/null
+++ b/src/opengl/qgraphicsshadereffect.cpp
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgraphicsshadereffect_p.h"
+#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
+#include "qglshaderprogram.h"
+#include "gl2paintengineex/qglcustomshaderstage_p.h"
+#define QGL_HAVE_CUSTOM_SHADERS 1
+#endif
+#include <QtGui/qpainter.h>
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/private/qgraphicseffect_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*#
+ \class QGraphicsShaderEffect
+ \brief The QGraphicsShaderEffect class is the base class for creating
+ custom GLSL shader effects in a QGraphicsScene.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ The specific effect is defined by a fragment of GLSL source code
+ supplied to setPixelShaderFragment(). This source code must define a
+ function with the signature
+ \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)}
+ that returns the source pixel value
+ to use in the paint engine's shader program. The shader fragment
+ is linked with the regular shader code used by the GL2 paint engine
+ to construct a complete QGLShaderProgram.
+
+ The following example shader converts the incoming pixmap to
+ grayscale and then applies a colorize operation using the
+ \c effectColor value:
+
+ \code
+ static char const colorizeShaderCode[] =
+ "uniform lowp vec4 effectColor;\n"
+ "lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) {\n"
+ " vec4 src = texture2D(imageTexture, textureCoords);\n"
+ " float gray = dot(src.rgb, vec3(0.212671, 0.715160, 0.072169));\n"
+ " vec4 colorize = 1.0-((1.0-gray)*(1.0-effectColor));\n"
+ " return vec4(colorize.rgb, src.a);\n"
+ "}";
+ \endcode
+
+ To use this shader code, it is necessary to define a subclass
+ of QGraphicsShaderEffect as follows:
+
+ \code
+ class ColorizeEffect : public QGraphicsShaderEffect
+ {
+ Q_OBJECT
+ public:
+ ColorizeEffect(QObject *parent = 0)
+ : QGraphicsShaderEffect(parent), color(Qt::black)
+ {
+ setPixelShaderFragment(colorizeShaderCode);
+ }
+
+ QColor effectColor() const { return color; }
+ void setEffectColor(const QColor& c)
+ {
+ color = c;
+ setUniformsDirty();
+ }
+
+ protected:
+ void setUniforms(QGLShaderProgram *program)
+ {
+ program->setUniformValue("effectColor", color);
+ }
+
+ private:
+ QColor color;
+ };
+ \endcode
+
+ The setUniforms() function is called when the effect is about
+ to be used for drawing to give the subclass the opportunity to
+ set effect-specific uniform variables.
+
+ QGraphicsShaderEffect is only supported when the GL2 paint engine
+ is in use. When any other paint engine is in use (GL1, raster, etc),
+ the drawItem() method will draw its item argument directly with
+ no effect applied.
+
+ \sa QGraphicsEffect
+*/
+
+static const char qglslDefaultImageFragmentShader[] = "\
+ lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) { \
+ return texture2D(imageTexture, textureCoords); \
+ }\n";
+
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+
+class QGLCustomShaderEffectStage : public QGLCustomShaderStage
+{
+public:
+ QGLCustomShaderEffectStage
+ (QGraphicsShaderEffect *e, const QByteArray& source)
+ : QGLCustomShaderStage(),
+ effect(e)
+ {
+ setSource(source);
+ }
+
+ void setUniforms(QGLShaderProgram *program);
+
+ QGraphicsShaderEffect *effect;
+};
+
+void QGLCustomShaderEffectStage::setUniforms(QGLShaderProgram *program)
+{
+ effect->setUniforms(program);
+}
+
+#endif
+
+class QGraphicsShaderEffectPrivate : public QGraphicsEffectPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsShaderEffect)
+public:
+ QGraphicsShaderEffectPrivate()
+ : pixelShaderFragment(qglslDefaultImageFragmentShader)
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ , customShaderStage(0)
+#endif
+ {
+ }
+
+ QByteArray pixelShaderFragment;
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ QGLCustomShaderEffectStage *customShaderStage;
+#endif
+};
+
+/*#
+ Constructs a shader effect and attaches it to \a parent.
+*/
+QGraphicsShaderEffect::QGraphicsShaderEffect(QObject *parent)
+ : QGraphicsEffect(*new QGraphicsShaderEffectPrivate(), parent)
+{
+}
+
+/*#
+ Destroys this shader effect.
+*/
+QGraphicsShaderEffect::~QGraphicsShaderEffect()
+{
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ Q_D(QGraphicsShaderEffect);
+ delete d->customShaderStage;
+#endif
+}
+
+/*#
+ Returns the source code for the pixel shader fragment for
+ this shader effect. The default is a shader that copies
+ its incoming pixmap directly to the output with no effect
+ applied.
+
+ \sa setPixelShaderFragment()
+*/
+QByteArray QGraphicsShaderEffect::pixelShaderFragment() const
+{
+ Q_D(const QGraphicsShaderEffect);
+ return d->pixelShaderFragment;
+}
+
+/*#
+ Sets the source code for the pixel shader fragment for
+ this shader effect to \a code.
+
+ The \a code must define a GLSL function with the signature
+ \c{lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords)}
+ that returns the source pixel value to use in the paint engine's
+ shader program. The following is the default pixel shader fragment,
+ which draws a pixmap with no effect applied:
+
+ \code
+ lowp vec4 customShader(lowp sampler2D imageTexture, highp vec2 textureCoords) {
+ return texture2D(imageTexture, textureCoords);
+ }
+ \endcode
+
+ \sa pixelShaderFragment(), setUniforms()
+*/
+void QGraphicsShaderEffect::setPixelShaderFragment(const QByteArray& code)
+{
+ Q_D(QGraphicsShaderEffect);
+ if (d->pixelShaderFragment != code) {
+ d->pixelShaderFragment = code;
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ delete d->customShaderStage;
+ d->customShaderStage = 0;
+#endif
+ }
+}
+
+/*#
+ \reimp
+*/
+void QGraphicsShaderEffect::draw(QPainter *painter)
+{
+ Q_D(QGraphicsShaderEffect);
+
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ // Set the custom shader on the paint engine. The setOnPainter()
+ // call may fail if the paint engine is not GL2. In that case,
+ // we fall through to drawing the pixmap normally.
+ if (!d->customShaderStage) {
+ d->customShaderStage = new QGLCustomShaderEffectStage
+ (this, d->pixelShaderFragment);
+ }
+ bool usingShader = d->customShaderStage->setOnPainter(painter);
+
+ QPoint offset;
+ if (sourceIsPixmap()) {
+ // No point in drawing in device coordinates (pixmap will be scaled anyways).
+ const QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset);
+ painter->drawPixmap(offset, pixmap);
+ } else {
+ // Draw pixmap in device coordinates to avoid pixmap scaling.
+ const QPixmap pixmap = sourcePixmap(Qt::DeviceCoordinates, &offset);
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+ painter->drawPixmap(offset, pixmap);
+ painter->setWorldTransform(restoreTransform);
+ }
+
+ // Remove the custom shader to return to normal painting operations.
+ if (usingShader)
+ d->customShaderStage->removeFromPainter(painter);
+#else
+ drawSource(painter);
+#endif
+}
+
+/*#
+ Sets the custom uniform variables on this shader effect to
+ be dirty. The setUniforms() function will be called the next
+ time the shader program corresponding to this effect is used.
+
+ This function is typically called by subclasses when an
+ effect-specific parameter is changed by the application.
+
+ \sa setUniforms()
+*/
+void QGraphicsShaderEffect::setUniformsDirty()
+{
+#ifdef QGL_HAVE_CUSTOM_SHADERS
+ Q_D(QGraphicsShaderEffect);
+ if (d->customShaderStage)
+ d->customShaderStage->setUniformsDirty();
+#endif
+}
+
+/*#
+ Sets custom uniform variables on the current GL context when
+ \a program is about to be used by the paint engine.
+
+ This function should be overridden if the shader set with
+ setPixelShaderFragment() has additional parameters beyond
+ those that the paint engine normally sets itself.
+
+ \sa setUniformsDirty()
+*/
+void QGraphicsShaderEffect::setUniforms(QGLShaderProgram *program)
+{
+ Q_UNUSED(program);
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qgraphicsshadereffect_p.h b/src/opengl/qgraphicsshadereffect_p.h
new file mode 100644
index 000000000..de65ebb60
--- /dev/null
+++ b/src/opengl/qgraphicsshadereffect_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGRAPHICSSHADEREFFECT_P_H
+#define QGRAPHICSSHADEREFFECT_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 <QtGui/qgraphicseffect.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(OpenGL)
+
+class QGLShaderProgram;
+class QGLCustomShaderEffectStage;
+class QGraphicsShaderEffectPrivate;
+
+class Q_OPENGL_EXPORT QGraphicsShaderEffect : public QGraphicsEffect
+{
+ Q_OBJECT
+public:
+ QGraphicsShaderEffect(QObject *parent = 0);
+ virtual ~QGraphicsShaderEffect();
+
+ QByteArray pixelShaderFragment() const;
+ void setPixelShaderFragment(const QByteArray& code);
+
+protected:
+ void draw(QPainter *painter);
+ void setUniformsDirty();
+ virtual void setUniforms(QGLShaderProgram *program);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsShaderEffect)
+ Q_DISABLE_COPY(QGraphicsShaderEffect)
+
+ friend class QGLCustomShaderEffectStage;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGRAPHICSSHADEREFFECT_P_H
diff --git a/src/opengl/qgraphicssystem_gl.cpp b/src/opengl/qgraphicssystem_gl.cpp
index 5eac03d79..c0d9233f9 100644
--- a/src/opengl/qgraphicssystem_gl.cpp
+++ b/src/opengl/qgraphicssystem_gl.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -47,12 +47,22 @@
#include "private/qgl_p.h"
#include <private/qwindowsurface_raster_p.h>
+#if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
+#include "private/qpixmapdata_x11gl_p.h"
+#include "private/qwindowsurface_x11gl_p.h"
+#endif
+
QT_BEGIN_NAMESPACE
extern QGLWidget *qt_gl_getShareWidget();
QPixmapData *QGLGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const
{
+#if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
+ if (type == QPixmapData::PixmapType && QX11GLPixmapData::hasX11GLPixmaps())
+ return new QX11GLPixmapData();
+#endif
+
return new QGLPixmapData(type);
}
@@ -66,6 +76,11 @@ QWindowSurface *QGLGraphicsSystem::createWindowSurface(QWidget *widget) const
return new QRasterWindowSurface(widget);
#endif
+#if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
+ if (QX11GLPixmapData::hasX11GLPixmaps())
+ return new QX11GLWindowSurface(widget);
+#endif
+
return new QGLWindowSurface(widget);
}
diff --git a/src/opengl/qgraphicssystem_gl_p.h b/src/opengl/qgraphicssystem_gl_p.h
index 71ad3cc16..b80e7a3f6 100644
--- a/src/opengl/qgraphicssystem_gl_p.h
+++ b/src/opengl/qgraphicssystem_gl_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp
index aa214f12f..8ab17a0f8 100644
--- a/src/opengl/qpaintengine_opengl.cpp
+++ b/src/opengl/qpaintengine_opengl.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -49,6 +49,7 @@
#include "qbrush.h"
#include "qgl.h"
#include <private/qgl_p.h>
+#include <private/qglpaintdevice_p.h>
#include <private/qpainter_p.h>
#include "qmap.h"
#include <private/qpaintengine_opengl_p.h>
@@ -65,7 +66,6 @@
#include "util/fragmentprograms_p.h"
#ifdef Q_WS_QWS
-#include "private/qglpaintdevice_qws_p.h"
#include "private/qglwindowsurface_qws_p.h"
#include "qwsmanager_qws.h"
#include "private/qwsmanager_p.h"
@@ -75,7 +75,7 @@
#include "qgl_cl_p.h"
#endif
-#define QGL_FUNC_CONTEXT QGLContext *ctx = const_cast<QGLContext *>(drawable.context());
+#define QGL_FUNC_CONTEXT QGLContext *ctx = const_cast<QGLContext *>(device->context());
#include <stdlib.h>
#include "qpaintengine_opengl_p.h"
@@ -248,8 +248,8 @@ public:
bound(false)
{
connect(QGLSignalProxy::instance(),
- SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupGLContextRefs(const QGLContext *)));
+ SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupGLContextRefs(const QGLContext*)));
}
inline void setDevice(QPaintDevice *pdev);
@@ -286,7 +286,7 @@ public Q_SLOTS:
}
private:
- QGLDrawable drawable;
+ QGLPaintDevice* device;
QGLFramebufferObject *offscreen;
QGLContext *ctx;
@@ -305,7 +305,13 @@ private:
inline void QGLOffscreen::setDevice(QPaintDevice *pdev)
{
- drawable.setDevice(pdev);
+ if (pdev->devType() == QInternal::OpenGL)
+ device = static_cast<QGLPaintDevice*>(pdev);
+ else
+ device = QGLPaintDevice::getDevice(pdev);
+
+ if (!device)
+ return;
drawable_fbo = (pdev->devType() == QInternal::FramebufferObject);
}
@@ -329,12 +335,12 @@ void QGLOffscreen::initialize()
activated = true;
initialized = true;
- int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(drawable.size().width(), drawable.size().height()))));
+ int dim = qMax(2048, static_cast<int>(qt_next_power_of_two(qMax(device->size().width(), device->size().height()))));
- bool shared_context = qgl_share_reg()->checkSharing(drawable.context(), ctx);
+ bool shared_context = QGLContext::areSharing(device->context(), ctx);
bool would_fail = last_failed_size.isValid() &&
- (drawable.size().width() >= last_failed_size.width() ||
- drawable.size().height() >= last_failed_size.height());
+ (device->size().width() >= last_failed_size.width() ||
+ device->size().height() >= last_failed_size.height());
bool needs_refresh = dim > mask_dim || !shared_context;
if (needs_refresh && !would_fail) {
@@ -348,13 +354,13 @@ void QGLOffscreen::initialize()
delete offscreen;
offscreen = 0;
mask_dim = 0;
- last_failed_size = drawable.size();
+ last_failed_size = device->size();
}
}
qt_mask_texture_cache()->setOffscreenSize(offscreenSize());
- qt_mask_texture_cache()->setDrawableSize(drawable.size());
- ctx = drawable.context();
+ qt_mask_texture_cache()->setDrawableSize(device->size());
+ ctx = device->context();
#endif
}
@@ -428,11 +434,11 @@ inline void QGLOffscreen::release()
DEBUG_ONCE_STR("QGLOffscreen: releasing offscreen");
if (drawable_fbo)
- drawable.makeCurrent();
+ device->ensureActiveTarget(); //###
else
offscreen->release();
- QSize sz(drawable.size());
+ QSize sz(device->size());
glViewport(0, 0, sz.width(), sz.height());
glMatrixMode(GL_PROJECTION);
@@ -455,7 +461,7 @@ inline bool QGLOffscreen::isBound() const
inline QSize QGLOffscreen::drawableSize() const
{
- return drawable.size();
+ return device->size();
}
inline QSize QGLOffscreen::offscreenSize() const
@@ -519,8 +525,8 @@ public:
QGLProgramCache() {
// we have to know when a context is deleted so we can free
// any program handles it holds
- connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupPrograms(const QGLContext *)));
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupPrograms(const QGLContext*)));
}
~QGLProgramCache() {
@@ -548,7 +554,7 @@ public:
QList<const QGLContext *> contexts = programs.uniqueKeys();
for (int i=0; i<contexts.size(); ++i) {
const QGLContext *cx = contexts.at(i);
- if (cx != ctx && qgl_share_reg()->checkSharing(cx, ctx)) {
+ if (cx != ctx && QGLContext::areSharing(cx, ctx)) {
QList<GLProgram> progs = programs.values(cx);
for (int k=0; k<progs.size(); ++k) {
const GLProgram &prg = progs.at(k);
@@ -633,8 +639,8 @@ public:
: p(priv)
{
connect(QGLSignalProxy::instance(),
- SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupGLContextRefs(const QGLContext *)));
+ SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupGLContextRefs(const QGLContext*)));
}
public Q_SLOTS:
@@ -740,7 +746,6 @@ public:
uint has_brush : 1;
uint has_fast_pen : 1;
uint use_stencil_method : 1;
- uint dirty_stencil : 1;
uint dirty_drawable_texture : 1;
uint has_stencil_face_ext : 1;
uint use_fragment_programs : 1;
@@ -751,13 +756,15 @@ public:
uint use_system_clip : 1;
uint use_emulation : 1;
+ QRegion dirty_stencil;
+
void updateUseEmulation();
QTransform matrix;
GLubyte pen_color[4];
GLubyte brush_color[4];
QTransform::TransformationType txop;
- QGLDrawable drawable;
+ QGLPaintDevice* device;
QGLOffscreen offscreen;
qreal inverseScale;
@@ -1003,12 +1010,12 @@ public:
QGLGradientCache() : QObject(), buffer_ctx(0)
{
connect(QGLSignalProxy::instance(),
- SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupGLContextRefs(const QGLContext *)));
+ SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupGLContextRefs(const QGLContext*)));
}
inline GLuint getBuffer(const QGradient &gradient, qreal opacity, QGLContext *ctx) {
- if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx))
+ if (buffer_ctx && !QGLContext::areSharing(buffer_ctx, ctx))
cleanCache();
buffer_ctx = ctx;
@@ -1070,6 +1077,7 @@ protected:
}
void cleanCache() {
+ QGLShareContextScope scope(buffer_ctx);
QGLGradientColorTableHash::const_iterator it = cache.constBegin();
for (; it != cache.constEnd(); ++it) {
const CacheInfo &cache_info = it.value();
@@ -1167,7 +1175,7 @@ void QOpenGLPaintEnginePrivate::createGradientPaletteTexture(const QGradient& g)
#ifdef QT_OPENGL_ES //###
Q_UNUSED(g);
#else
- GLuint texId = qt_opengl_gradient_cache()->getBuffer(g, opacity, drawable.context());
+ GLuint texId = qt_opengl_gradient_cache()->getBuffer(g, opacity, device->context());
glBindTexture(GL_TEXTURE_1D, texId);
grad_palette = texId;
if (g.spread() == QGradient::RepeatSpread || g.type() == QGradient::ConicalGradient)
@@ -1214,7 +1222,7 @@ inline void QOpenGLPaintEnginePrivate::setGradientOps(const QBrush &brush, const
fragment_brush = FRAGMENT_PROGRAM_BRUSH_CONICAL;
else if (current_style == Qt::SolidPattern)
fragment_brush = FRAGMENT_PROGRAM_BRUSH_SOLID;
- else if (current_style == Qt::TexturePattern)
+ else if (current_style == Qt::TexturePattern && !brush.texture().isQBitmap())
fragment_brush = FRAGMENT_PROGRAM_BRUSH_TEXTURE;
else
fragment_brush = FRAGMENT_PROGRAM_BRUSH_PATTERN;
@@ -1236,16 +1244,25 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
{
Q_D(QOpenGLPaintEngine);
- d->drawable.setDevice(pdev);
+ if (pdev->devType() == QInternal::OpenGL)
+ d->device = static_cast<QGLPaintDevice*>(pdev);
+ else
+ d->device = QGLPaintDevice::getDevice(pdev);
+
+ if (!d->device)
+ return false;
+
d->offscreen.setDevice(pdev);
d->has_fast_pen = false;
d->inverseScale = 1;
d->opacity = 1;
- d->drawable.makeCurrent();
+ d->device->beginPaint();
d->matrix = QTransform();
d->has_antialiasing = false;
d->high_quality_antialiasing = false;
- d->dirty_stencil = true;
+
+ QSize sz(d->device->size());
+ d->dirty_stencil = QRect(0, 0, sz.width(), sz.height());
d->use_emulation = false;
@@ -1256,7 +1273,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
bool has_frag_program = (QGLExtensions::glExtensions & QGLExtensions::FragmentProgram)
&& (pdev->devType() != QInternal::Pixmap);
- QGLContext *ctx = const_cast<QGLContext *>(d->drawable.context());
+ QGLContext *ctx = const_cast<QGLContext *>(d->device->context());
if (!ctx) {
qWarning() << "QOpenGLPaintEngine: paint device doesn't have a valid GL context.";
return false;
@@ -1265,9 +1282,9 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
if (has_frag_program)
has_frag_program = qt_resolve_frag_program_extensions(ctx) && qt_resolve_version_1_3_functions(ctx);
- d->use_stencil_method = d->drawable.format().stencil()
+ d->use_stencil_method = d->device->format().stencil()
&& (QGLExtensions::glExtensions & QGLExtensions::StencilWrap);
- if (d->drawable.format().directRendering()
+ if (d->device->format().directRendering()
&& (d->use_stencil_method && QGLExtensions::glExtensions & QGLExtensions::StencilTwoSide))
d->has_stencil_face_ext = qt_resolve_stencil_face_extension(ctx);
@@ -1333,23 +1350,6 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
d->offscreen.begin();
- if (d->drawable.context()->d_func()->clear_on_painter_begin && d->drawable.autoFillBackground()) {
-
- if (d->drawable.hasTransparentBackground())
- glClearColor(0.0, 0.0, 0.0, 0.0);
- else {
- const QColor &c = d->drawable.backgroundColor();
- glClearColor(c.redF(), c.greenF(), c.blueF(), 1.0);
- }
-
- GLbitfield clearBits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT;
-#ifndef QT_OPENGL_ES
- clearBits |= GL_ACCUM_BUFFER_BIT;
-#endif
- glClear(clearBits);
- }
-
- QSize sz(d->drawable.size());
glViewport(0, 0, sz.width(), sz.height()); // XXX (Embedded): We need a solution for GLWidgets that draw in a part or a bigger surface...
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@@ -1366,7 +1366,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
#ifdef QT_OPENGL_ES
d->max_texture_size = ctx->d_func()->maxTextureSize();
#else
- bool shared_ctx = qgl_share_reg()->checkSharing(d->drawable.context(), d->shader_ctx);
+ bool shared_ctx = QGLContext::areSharing(d->device->context(), d->shader_ctx);
if (shared_ctx) {
d->max_texture_size = d->shader_ctx->d_func()->maxTextureSize();
@@ -1382,7 +1382,7 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev)
glDeleteTextures(1, &d->drawable_texture);
ctx->makeCurrent();
}
- d->shader_ctx = d->drawable.context();
+ d->shader_ctx = d->device->context();
glGenTextures(1, &d->grad_palette);
qt_mask_texture_cache()->clearCache();
@@ -1417,7 +1417,7 @@ bool QOpenGLPaintEngine::end()
Q_D(QOpenGLPaintEngine);
d->flushDrawQueue();
d->offscreen.end();
- QGLContext *ctx = const_cast<QGLContext *>(d->drawable.context());
+ QGLContext *ctx = const_cast<QGLContext *>(d->device->context());
if (!ctx->d_ptr->internal_context) {
glMatrixMode(GL_TEXTURE);
glPopMatrix();
@@ -1434,8 +1434,7 @@ bool QOpenGLPaintEngine::end()
glPopClientAttrib();
}
#endif
- d->drawable.swapBuffers();
- d->drawable.doneCurrent();
+ d->device->endPaint();
qt_mask_texture_cache()->maintainCache();
return true;
@@ -1598,7 +1597,8 @@ void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF
qreal realRadius = g->radius();
QTransform translate(1, 0, 0, 1, -realFocal.x(), -realFocal.y());
QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
- QTransform inv_matrix = gl_to_qt * matrix.inverted() * brush.transform().inverted() * translate;
+ QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
+ QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted() * translate;
setInvMatrixData(inv_matrix);
@@ -1611,7 +1611,8 @@ void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF
QPointF realCenter = g->center();
QTransform translate(1, 0, 0, 1, -realCenter.x(), -realCenter.y());
QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
- QTransform inv_matrix = gl_to_qt * matrix.inverted() * brush.transform().inverted() * translate;
+ QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
+ QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted() * translate;
setInvMatrixData(inv_matrix);
@@ -1623,8 +1624,8 @@ void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF
QPointF realFinal = g->finalStop();
QTransform translate(1, 0, 0, 1, -realStart.x(), -realStart.y());
QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
-
- QTransform inv_matrix = gl_to_qt * matrix.inverted() * brush.transform().inverted() * translate;
+ QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
+ QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted() * translate;
setInvMatrixData(inv_matrix);
@@ -1635,10 +1636,9 @@ void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF
linear_data[2] = 1.0f / (l.x() * l.x() + l.y() * l.y());
} else if (style != Qt::SolidPattern) {
- QTransform translate(1, 0, 0, 1, brush_origin.x(), brush_origin.y());
QTransform gl_to_qt(1, 0, 0, -1, 0, pdev->height());
-
- QTransform inv_matrix = gl_to_qt * matrix.inverted() * brush.transform().inverted() * translate;
+ QTransform m = QTransform(matrix).translate(brush_origin.x(), brush_origin.y());
+ QTransform inv_matrix = gl_to_qt * (brush.transform() * m).inverted();
setInvMatrixData(inv_matrix);
}
@@ -1951,34 +1951,34 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule)
{
Q_Q(QOpenGLPaintEngine);
- if (dirty_stencil) {
- disableClipping();
+ QRect rect = dirty_stencil.boundingRect();
- if (use_system_clip) {
- glEnable(GL_SCISSOR_TEST);
+ if (use_system_clip)
+ rect = q->systemClip().intersected(dirty_stencil).boundingRect();
- QRect rect = q->systemClip().boundingRect();
+ glStencilMask(~0);
- const int left = rect.left();
- const int width = rect.width();
- const int bottom = drawable.size().height() - (rect.bottom() + 1);
- const int height = rect.height();
+ if (!rect.isEmpty()) {
+ disableClipping();
- glScissor(left, bottom, width, height);
- }
+ glEnable(GL_SCISSOR_TEST);
+
+ const int left = rect.left();
+ const int width = rect.width();
+ const int bottom = device->size().height() - (rect.bottom() + 1);
+ const int height = rect.height();
+
+ glScissor(left, bottom, width, height);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
- dirty_stencil = false;
+ dirty_stencil -= rect;
- if (use_system_clip)
- glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_SCISSOR_TEST);
enableClipping();
}
- glStencilMask(~0);
-
// Enable stencil.
glEnable(GL_STENCIL_TEST);
@@ -2118,7 +2118,7 @@ void QOpenGLPaintEngine::updatePen(const QPen &pen)
Qt::PenStyle pen_style = pen.style();
d->pen_brush_style = pen.brush().style();
d->cpen = pen;
- d->has_pen = (pen_style != Qt::NoPen);
+ d->has_pen = (pen_style != Qt::NoPen) && (d->pen_brush_style != Qt::NoBrush);
d->updateUseEmulation();
if (pen.isCosmetic()) {
@@ -2242,7 +2242,7 @@ void QOpenGLPaintEnginePrivate::updateDepthClip()
const int left = fastClip.left();
const int width = fastClip.width();
- const int bottom = drawable.size().height() - (fastClip.bottom() + 1);
+ const int bottom = device->size().height() - (fastClip.bottom() + 1);
const int height = fastClip.height();
glScissor(left, bottom, width, height);
@@ -2313,7 +2313,7 @@ void QOpenGLPaintEnginePrivate::updateDepthClip()
void QOpenGLPaintEnginePrivate::systemStateChanged()
{
Q_Q(QOpenGLPaintEngine);
- if (q->state()->hasClipping)
+ if (q->painter()->hasClipping())
q->updateClipRegion(q->painter()->clipRegion(), Qt::ReplaceClip);
else
q->updateClipRegion(QRegion(), Qt::NoClip);
@@ -2325,7 +2325,7 @@ void QOpenGLPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOpe
// clipping is only supported when a stencil or depth buffer is
// available
- if (!d->drawable.format().depth())
+ if (!d->device->format().depth())
return;
d->use_system_clip = false;
@@ -2362,7 +2362,7 @@ void QOpenGLPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOpe
path.addRect(untransformedRects[0]);
path = d->matrix.map(path);
- if (path.contains(QRectF(QPointF(), d->drawable.size())))
+ if (path.contains(QRectF(QPointF(), d->device->size())))
isScreenClip = true;
}
}
@@ -3369,7 +3369,7 @@ void QOpenGLPaintEnginePrivate::drawOffscreenPath(const QPainterPath &path)
disableClipping();
- GLuint program = qt_gl_program_cache()->getProgram(drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(device->context(),
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true);
QGLPathMaskGenerator maskGenerator(path, matrix, offscreen, program);
addItem(qt_mask_texture_cache()->getMask(maskGenerator, this));
@@ -3506,7 +3506,7 @@ void QOpenGLPaintEngine::drawRects(const QRectF *rects, int rectCount)
if (d->has_brush) {
d->disableClipping();
- GLuint program = qt_gl_program_cache()->getProgram(d->drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(d->device->context(),
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true);
if (d->matrix.type() >= QTransform::TxProject) {
@@ -3916,7 +3916,7 @@ void QOpenGLPaintEnginePrivate::strokeLines(const QPainterPath &path)
qreal penWidth = cpen.widthF();
- GLuint program = qt_gl_program_cache()->getProgram(drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(device->context(),
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA, 0, true);
QGLLineMaskGenerator maskGenerator(path, matrix, penWidth == 0 ? 1.0 : penWidth,
offscreen, program);
@@ -4302,14 +4302,26 @@ void QOpenGLPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QR
else {
GLenum target = qt_gl_preferredTextureTarget();
d->flushDrawQueue();
- d->drawable.bindTexture(pm, target);
- drawTextureRect(pm.width(), pm.height(), r, sr, target);
+ QGLTexture *tex =
+ d->device->context()->d_func()->bindTexture(pm, target, GL_RGBA,
+ QGLContext::InternalBindOption);
+ drawTextureRect(pm.width(), pm.height(), r, sr, target, tex);
}
}
void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &offset)
{
Q_D(QOpenGLPaintEngine);
+ if (pm.depth() == 1) {
+ QPixmap tpx(pm.size());
+ tpx.fill(Qt::transparent);
+ QPainter p(&tpx);
+ p.setPen(d->cpen);
+ p.drawPixmap(0, 0, pm);
+ p.end();
+ drawTiledPixmap(r, tpx, offset);
+ return;
+ }
QImage scaled;
const int sz = d->max_texture_size;
@@ -4335,10 +4347,13 @@ void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con
} else {
d->flushDrawQueue();
+ QGLTexture *tex;
if (scaled.isNull())
- d->drawable.bindTexture(pm);
+ tex = d->device->context()->d_func()->bindTexture(pm, GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption);
else
- d->drawable.bindTexture(scaled);
+ tex = d->device->context()->d_func()->bindTexture(scaled, GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption);
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, d->use_smooth_pixmap_transform);
#ifndef QT_OPENGL_ES
@@ -4353,10 +4368,12 @@ void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con
// Rotate the texture so that it is aligned correctly and the
// wrapping is done correctly
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- glRotatef(180.0, 0.0, 1.0, 0.0);
- glRotatef(180.0, 0.0, 0.0, 1.0);
+ if (tex->options & QGLContext::InvertedYBindOption) {
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glRotatef(180.0, 0.0, 1.0, 0.0);
+ glRotatef(180.0, 0.0, 0.0, 1.0);
+ }
q_vertexType vertexArray[4*2];
q_vertexType texCoordArray[4*2];
@@ -4376,7 +4393,8 @@ void QOpenGLPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, con
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
- glPopMatrix();
+ if (tex->options & QGLContext::InvertedYBindOption)
+ glPopMatrix();
glDisable(GL_TEXTURE_2D);
#ifndef QT_OPENGL_ES
@@ -4412,13 +4430,15 @@ void QOpenGLPaintEngine::drawImage(const QRectF &r, const QImage &image, const Q
else {
GLenum target = qt_gl_preferredTextureTarget();
d->flushDrawQueue();
- d->drawable.bindTexture(image, target);
- drawTextureRect(image.width(), image.height(), r, sr, target);
+ QGLTexture *tex =
+ d->device->context()->d_func()->bindTexture(image, target, GL_RGBA,
+ QGLContext::InternalBindOption);
+ drawTextureRect(image.width(), image.height(), r, sr, target, tex);
}
}
void QOpenGLPaintEngine::drawTextureRect(int tx_width, int tx_height, const QRectF &r,
- const QRectF &sr, GLenum target)
+ const QRectF &sr, GLenum target, QGLTexture *tex)
{
Q_D(QOpenGLPaintEngine);
#ifndef QT_OPENGL_ES
@@ -4433,13 +4453,18 @@ void QOpenGLPaintEngine::drawTextureRect(int tx_width, int tx_height, const QRec
if (target == GL_TEXTURE_2D) {
x1 = sr.x() / tx_width;
x2 = x1 + sr.width() / tx_width;
- y1 = 1.0 - (sr.bottom() / tx_height);
- y2 = 1.0 - (sr.y() / tx_height);
+ if (tex->options & QGLContext::InvertedYBindOption) {
+ y1 = 1 - (sr.bottom() / tx_height);
+ y2 = 1 - (sr.y() / tx_height);
+ } else {
+ y1 = sr.bottom() / tx_height;
+ y2 = sr.y() / tx_height;
+ }
} else {
x1 = sr.x();
x2 = sr.right();
- y1 = tx_height - sr.bottom();
- y2 = tx_height - sr.y();
+ y1 = sr.bottom();
+ y2 = sr.y();
}
q_vertexType vertexArray[4*2];
@@ -4670,7 +4695,7 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti,
QList<const QGLContext *> contexts = qt_context_cache.keys();
for (int i=0; i<contexts.size(); ++i) {
const QGLContext *ctx = contexts.at(i);
- if (ctx != context && qgl_share_reg()->checkSharing(context, ctx)) {
+ if (ctx != context && QGLContext::areSharing(context, ctx)) {
context_key = ctx;
dev_it = qt_context_cache.constFind(context_key);
break;
@@ -4687,8 +4712,8 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti,
QWidget *widget = static_cast<QWidget *>(context->device());
connect(widget, SIGNAL(destroyed(QObject*)), SLOT(widgetDestroyed(QObject*)));
connect(QGLSignalProxy::instance(),
- SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupContext(const QGLContext *)));
+ SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(cleanupContext(const QGLContext*)));
}
} else {
font_cache = dev_it.value();
@@ -4777,7 +4802,8 @@ void QGLGlyphCache::cacheGlyphs(QGLContext *context, const QTextItemInt &ti,
}
}
- QImage glyph_im(ti.fontEngine->alphaMapForGlyph(glyphs[i]).convertToFormat(QImage::Format_Indexed8));
+ QImage glyph_im(ti.fontEngine->alphaMapForGlyph(glyphs[i]));
+ glyph_im = glyph_im.convertToFormat(QImage::Format_Indexed8);
glyph_width = glyph_im.width();
Q_ASSERT(glyph_width >= 0);
// pad the glyph width to an even number
@@ -4879,7 +4905,7 @@ void QOpenGLPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
// make sure the glyphs we want to draw are in the cache
- qt_glyph_cache()->cacheGlyphs(d->drawable.context(), ti, glyphs);
+ qt_glyph_cache()->cacheGlyphs(d->device->context(), ti, glyphs);
d->setGradientOps(Qt::SolidPattern, QRectF()); // turns off gradient ops
qt_glColor4ubv(d->pen_color);
@@ -4957,7 +4983,7 @@ void QOpenGLPaintEngine::drawEllipse(const QRectF &rect)
glPushMatrix();
glLoadIdentity();
- GLuint program = qt_gl_program_cache()->getProgram(d->drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(d->device->context(),
FRAGMENT_PROGRAM_MASK_ELLIPSE_AA, 0, true);
QGLEllipseMaskGenerator maskGenerator(rect,
d->matrix,
@@ -5092,10 +5118,10 @@ void QOpenGLPaintEnginePrivate::copyDrawable(const QRectF &rect)
QRectF screen_rect = rect.adjusted(-1, -1, 1, 1);
int left = qMax(0, static_cast<int>(screen_rect.left()));
- int width = qMin(drawable.size().width() - left, static_cast<int>(screen_rect.width()) + 1);
+ int width = qMin(device->size().width() - left, static_cast<int>(screen_rect.width()) + 1);
- int bottom = qMax(0, static_cast<int>(drawable.size().height() - screen_rect.bottom()));
- int height = qMin(drawable.size().height() - bottom, static_cast<int>(screen_rect.height()) + 1);
+ int bottom = qMax(0, static_cast<int>(device->size().height() - screen_rect.bottom()));
+ int height = qMin(device->size().height() - bottom, static_cast<int>(screen_rect.height()) + 1);
glBindTexture(GL_TEXTURE_2D, drawable_texture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, left, bottom, width, height);
@@ -5189,9 +5215,12 @@ void QOpenGLPaintEnginePrivate::composite(GLuint primitive, const q_vertexType *
glActiveTexture(GL_TEXTURE0 + brush_texture_location);
if (current_style == Qt::TexturePattern)
- drawable.bindTexture(cbrush.textureImage());
+ device->context()->d_func()->bindTexture(cbrush.textureImage(), GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption);
else
- drawable.bindTexture(qt_imageForBrush(current_style, true));
+ device->context()->d_func()->bindTexture(qt_imageForBrush(current_style, false),
+ GL_TEXTURE_2D, GL_RGBA,
+ QGLContext::InternalBindOption);
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, use_smooth_pixmap_transform);
}
@@ -5199,7 +5228,7 @@ void QOpenGLPaintEnginePrivate::composite(GLuint primitive, const q_vertexType *
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, q_vertexTypeEnum, 0, vertexArray);
glEnable(GL_FRAGMENT_PROGRAM_ARB);
- GLuint program = qt_gl_program_cache()->getProgram(drawable.context(),
+ GLuint program = qt_gl_program_cache()->getProgram(device->context(),
fragment_brush,
fragment_composition_mode, false);
glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program);
@@ -5271,7 +5300,7 @@ void QOpenGLPaintEnginePrivate::drawItem(const QDrawQueueItem &item)
setGradientOps(item.brush, item.location.screen_rect);
composite(item.location.screen_rect, item.location.rect.topLeft() - item.location.screen_rect.topLeft()
- - QPoint(0, offscreen.offscreenSize().height() - drawable.size().height()));
+ - QPoint(0, offscreen.offscreenSize().height() - device->size().height()));
}
void QOpenGLPaintEnginePrivate::flushDrawQueue()
@@ -5420,7 +5449,7 @@ void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
QPainter *p = painter();
QBrush oldBrush = p->brush();
p->setBrush(brush);
- qt_draw_helper(p->d_ptr, painterPathFromVectorPath(path), QPainterPrivate::FillDraw);
+ qt_draw_helper(p->d_ptr.data(), painterPathFromVectorPath(path), QPainterPrivate::FillDraw);
p->setBrush(oldBrush);
return;
}
@@ -5592,17 +5621,6 @@ void QOpenGLPaintEnginePrivate::ensureDrawableTexture()
#endif
}
-QPixmapFilter *QOpenGLPaintEngine::createPixmapFilter(int type) const
-{
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
- if (QGLContext::currentContext())
- return QGLContext::currentContext()->d_func()->createPixmapFilter(type);
- else
-#endif
- return 0;
-}
-
-
QT_END_NAMESPACE
#include "qpaintengine_opengl.moc"
diff --git a/src/opengl/qpaintengine_opengl_p.h b/src/opengl/qpaintengine_opengl_p.h
index 371126159..4fea63832 100644
--- a/src/opengl/qpaintengine_opengl_p.h
+++ b/src/opengl/qpaintengine_opengl_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -58,6 +58,7 @@
QT_BEGIN_NAMESPACE
class QOpenGLPaintEnginePrivate;
+class QGLTexture;
class QOpenGLPaintEngineState : public QPainterState
{
@@ -135,8 +136,6 @@ public:
void drawEllipse(const QRectF &rect);
- QPixmapFilter *createPixmapFilter(int type) const;
-
#ifdef Q_WS_WIN
HDC handle() const;
#else
@@ -146,7 +145,8 @@ public:
private:
void drawPolyInternal(const QPolygonF &pa, bool close = true);
- void drawTextureRect(int tx_width, int tx_height, const QRectF &r, const QRectF &sr, GLenum target);
+ void drawTextureRect(int tx_width, int tx_height, const QRectF &r, const QRectF &sr,
+ GLenum target, QGLTexture *tex);
Q_DISABLE_COPY(QOpenGLPaintEngine)
};
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index 8de1aae36..fb55097e5 100644
--- a/src/opengl/qpixmapdata_gl.cpp
+++ b/src/opengl/qpixmapdata_gl.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -48,49 +48,194 @@
#include <private/qgl_p.h>
#include <private/qdrawhelper_p.h>
+#include <private/qimage_p.h>
#include <private/qpaintengineex_opengl2_p.h>
+#include <qdesktopwidget.h>
+
QT_BEGIN_NAMESPACE
extern QGLWidget* qt_gl_share_widget();
-class QGLShareContextScope
-{
-public:
- QGLShareContextScope(const QGLContext *ctx)
- : m_oldContext(0)
- {
- QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
- if (currentContext != ctx && !qgl_share_reg()->checkSharing(ctx, currentContext)) {
- m_oldContext = currentContext;
- m_ctx = const_cast<QGLContext *>(ctx);
- m_ctx->makeCurrent();
- } else {
- m_ctx = currentContext;
+/*!
+ \class QGLFramebufferObjectPool
+ \since 4.6
+
+ \brief The QGLFramebufferObject class provides a pool of framebuffer
+ objects for offscreen rendering purposes.
+
+ When requesting an FBO of a given size and format, an FBO of the same
+ format and a size at least as big as the requested size will be returned.
+
+ \internal
+*/
+
+static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo)
+{
+ return qAbs(size.width() * size.height() - fbo->width() * fbo->height());
+}
+
+extern int qt_next_power_of_two(int v);
+
+static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz)
+{
+#ifdef QT_OPENGL_ES_2
+ QSize rounded(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height()));
+ if (rounded.width() * rounded.height() < 1.20 * sz.width() * sz.height())
+ return rounded;
+#endif
+ return sz;
+}
+
+
+QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize)
+{
+ QGLFramebufferObject *chosen = 0;
+ QGLFramebufferObject *candidate = 0;
+ for (int i = 0; !chosen && i < m_fbos.size(); ++i) {
+ QGLFramebufferObject *fbo = m_fbos.at(i);
+
+ if (strictSize) {
+ if (fbo->size() == requestSize && fbo->format() == requestFormat) {
+ chosen = fbo;
+ break;
+ } else {
+ continue;
+ }
}
+
+ if (fbo->format() == requestFormat) {
+ // choose the fbo with a matching format and the closest size
+ if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo))
+ candidate = fbo;
+ }
+
+ if (candidate) {
+ m_fbos.removeOne(candidate);
+
+ const QSize fboSize = candidate->size();
+ QSize sz = fboSize;
+
+ if (sz.width() < requestSize.width())
+ sz.setWidth(qMax(requestSize.width(), qRound(sz.width() * 1.5)));
+ if (sz.height() < requestSize.height())
+ sz.setHeight(qMax(requestSize.height(), qRound(sz.height() * 1.5)));
+
+ // wasting too much space?
+ if (sz.width() * sz.height() > requestSize.width() * requestSize.height() * 4)
+ sz = requestSize;
+
+ if (sz != fboSize) {
+ delete candidate;
+ candidate = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(sz), requestFormat);
+ }
+
+ chosen = candidate;
+ }
+ }
+
+ if (!chosen) {
+ if (strictSize)
+ chosen = new QGLFramebufferObject(requestSize, requestFormat);
+ else
+ chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat);
}
- operator QGLContext *()
- {
- return m_ctx;
+ if (!chosen->isValid()) {
+ delete chosen;
+ chosen = 0;
}
- QGLContext *operator->()
- {
- return m_ctx;
+ return chosen;
+}
+
+void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo)
+{
+ if (fbo)
+ m_fbos << fbo;
+}
+
+
+QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const
+{
+ return data->paintEngine();
+}
+
+void QGLPixmapGLPaintDevice::beginPaint()
+{
+ if (!data->isValid())
+ return;
+
+ // QGLPaintDevice::beginPaint will store the current binding and replace
+ // it with m_thisFBO:
+ m_thisFBO = data->m_renderFbo->handle();
+ QGLPaintDevice::beginPaint();
+
+ Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2);
+
+ // QPixmap::fill() is deferred until now, where we actually need to do the fill:
+ if (data->needsFill()) {
+ const QColor &c = data->fillColor();
+ float alpha = c.alphaF();
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha);
+ glClear(GL_COLOR_BUFFER_BIT);
}
+ else if (!data->isUninitialized()) {
+ // If the pixmap (GL Texture) has valid content (it has been
+ // uploaded from an image or rendered into before), we need to
+ // copy it from the texture to the render FBO.
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+
+#if !defined(QT_OPENGL_ES_2)
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, data->width(), data->height(), 0, -999999, 999999);
+#endif
- ~QGLShareContextScope()
- {
- if (m_oldContext)
- m_oldContext->makeCurrent();
+ glViewport(0, 0, data->width(), data->height());
+
+ // Pass false to bind so it doesn't copy the FBO into the texture!
+ context()->drawTexture(QRect(0, 0, data->width(), data->height()), data->bind(false));
}
+}
-private:
- QGLContext *m_oldContext;
- QGLContext *m_ctx;
-};
+void QGLPixmapGLPaintDevice::endPaint()
+{
+ if (!data->isValid())
+ return;
+
+ data->copyBackFromRenderFbo(false);
+
+ // Base's endPaint will restore the previous FBO binding
+ QGLPaintDevice::endPaint();
+
+ qgl_fbo_pool()->release(data->m_renderFbo);
+ data->m_renderFbo = 0;
+}
+
+QGLContext* QGLPixmapGLPaintDevice::context() const
+{
+ data->ensureCreated();
+ return data->m_ctx;
+}
+
+QSize QGLPixmapGLPaintDevice::size() const
+{
+ return data->size();
+}
+
+void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d)
+{
+ data = d;
+}
static int qt_gl_pixmap_serial = 0;
@@ -104,6 +249,7 @@ QGLPixmapData::QGLPixmapData(PixelType type)
, m_hasAlpha(false)
{
setSerialNumber(++qt_gl_pixmap_serial);
+ m_glDevice.setPixmapData(this);
}
QGLPixmapData::~QGLPixmapData()
@@ -112,12 +258,19 @@ QGLPixmapData::~QGLPixmapData()
if (!shareWidget)
return;
+ delete m_engine;
+
if (m_texture.id) {
QGLShareContextScope ctx(shareWidget->context());
glDeleteTextures(1, &m_texture.id);
}
}
+QPixmapData *QGLPixmapData::createCompatiblePixmapData() const
+{
+ return new QGLPixmapData(pixelType());
+}
+
bool QGLPixmapData::isValid() const
{
return w > 0 && h > 0;
@@ -129,7 +282,7 @@ bool QGLPixmapData::isValidContext(const QGLContext *ctx) const
return true;
const QGLContext *share_ctx = qt_gl_share_widget()->context();
- return ctx == share_ctx || qgl_share_reg()->checkSharing(ctx, share_ctx);
+ return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx);
}
void QGLPixmapData::resize(int width, int height)
@@ -192,16 +345,11 @@ void QGLPixmapData::ensureCreated() const
m_source = QImage();
}
- m_texture.clean = false;
-}
-
-QGLFramebufferObject *QGLPixmapData::fbo() const
-{
- return m_renderFbo;
+ m_texture.options &= ~QGLContext::MemoryManagedBindOption;
}
void QGLPixmapData::fromImage(const QImage &image,
- Qt::ImageConversionFlags)
+ Qt::ImageConversionFlags /*flags*/)
{
if (image.size() == QSize(w, h))
setSerialNumber(++qt_gl_pixmap_serial);
@@ -209,20 +357,26 @@ void QGLPixmapData::fromImage(const QImage &image,
if (pixelType() == BitmapType) {
m_source = image.convertToFormat(QImage::Format_MonoLSB);
+
} else {
- m_source = image.hasAlphaChannel()
- ? image.convertToFormat(QImage::Format_ARGB32_Premultiplied)
- : image.convertToFormat(QImage::Format_RGB32);
+ QImage::Format format = QImage::Format_RGB32;
+ if (qApp->desktop()->depth() == 16)
+ format = QImage::Format_RGB16;
+
+ if (image.hasAlphaChannel() && const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels())
+ format = QImage::Format_ARGB32_Premultiplied;;
+
+ m_source = image.convertToFormat(format);
}
m_dirty = true;
m_hasFillColor = false;
- m_hasAlpha = image.hasAlphaChannel();
+ m_hasAlpha = m_source.hasAlphaChannel();
w = image.width();
h = image.height();
is_null = (w <= 0 || h <= 0);
- d = pixelType() == QPixmapData::PixmapType ? 32 : 1;
+ d = m_source.depth();
if (m_texture.id) {
QGLShareContextScope ctx(qt_gl_share_widget()->context());
@@ -270,8 +424,20 @@ void QGLPixmapData::fill(const QColor &color)
m_hasFillColor = true;
m_fillColor = color;
} else {
- QImage image = fillImage(color);
- fromImage(image, 0);
+
+ if (m_source.isNull()) {
+ m_fillColor = color;
+ m_hasFillColor = true;
+
+ } else if (m_source.depth() == 32) {
+ m_source.fill(PREMUL(color.rgba()));
+
+ } else if (m_source.depth() == 1) {
+ if (color == Qt::color1)
+ m_source.fill(1);
+ else
+ m_source.fill(0);
+ }
}
}
@@ -285,15 +451,15 @@ QImage QGLPixmapData::fillImage(const QColor &color) const
QImage img;
if (pixelType() == BitmapType) {
img = QImage(w, h, QImage::Format_MonoLSB);
- img.setNumColors(2);
+
+ img.setColorCount(2);
img.setColor(0, QColor(Qt::color0).rgba());
img.setColor(1, QColor(Qt::color1).rgba());
- int gray = qGray(color.rgba());
- if (qAbs(255 - gray) < gray)
- img.fill(0);
- else
+ if (color == Qt::color1)
img.fill(1);
+ else
+ img.fill(0);
} else {
img = QImage(w, h,
m_hasAlpha
@@ -332,8 +498,11 @@ struct TextureBuffer
QGL2PaintEngineEx *engine;
};
-static QVector<TextureBuffer> textureBufferStack;
-static int currentTextureBuffer = 0;
+Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool)
+QGLFramebufferObjectPool* qgl_fbo_pool()
+{
+ return _qgl_fbo_pool();
+}
void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
{
@@ -350,8 +519,8 @@ void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
if (!ctx->d_ptr->fbo)
glGenFramebuffers(1, &ctx->d_ptr->fbo);
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
- glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, m_texture.id, 0);
const int x0 = 0;
@@ -359,7 +528,8 @@ void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
const int y0 = 0;
const int y1 = h;
- glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle());
+ if (!m_renderFbo->isBound())
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle());
glDisable(GL_SCISSOR_TEST);
@@ -368,47 +538,12 @@ void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
GL_COLOR_BUFFER_BIT,
GL_NEAREST);
- if (keepCurrentFboBound)
+ if (keepCurrentFboBound) {
glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
-}
-
-void QGLPixmapData::swapBuffers()
-{
- if (!isValid())
- return;
-
- copyBackFromRenderFbo(false);
- m_renderFbo->release();
-
- --currentTextureBuffer;
-
- m_renderFbo = 0;
- m_engine = 0;
-}
-
-void QGLPixmapData::makeCurrent()
-{
- if (isValid() && m_renderFbo)
- m_renderFbo->bind();
-}
-
-void QGLPixmapData::doneCurrent()
-{
- if (isValid() && m_renderFbo)
- m_renderFbo->release();
-}
-
-static TextureBuffer createTextureBuffer(const QSize &size, QGL2PaintEngineEx *engine = 0)
-{
- TextureBuffer buffer;
- QGLFramebufferObjectFormat fmt;
- fmt.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
- fmt.setSamples(4);
-
- buffer.fbo = new QGLFramebufferObject(size, fmt);
- buffer.engine = engine ? engine : new QGL2PaintEngineEx;
-
- return buffer;
+ } else {
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_renderFbo->handle());
+ ctx->d_ptr->current_fbo = m_renderFbo->handle();
+ }
}
bool QGLPixmapData::useFramebufferObjects()
@@ -423,7 +558,7 @@ QPaintEngine* QGLPixmapData::paintEngine() const
if (!isValid())
return 0;
- if (m_engine)
+ if (m_renderFbo)
return m_engine;
if (useFramebufferObjects()) {
@@ -433,33 +568,16 @@ QPaintEngine* QGLPixmapData::paintEngine() const
qt_gl_share_widget()->makeCurrent();
QGLShareContextScope ctx(qt_gl_share_widget()->context());
- if (textureBufferStack.size() <= currentTextureBuffer) {
- textureBufferStack << createTextureBuffer(size());
- } else {
- QSize sz = textureBufferStack.at(currentTextureBuffer).fbo->size();
- if (sz.width() < w || sz.height() < h) {
- if (sz.width() < w)
- sz.setWidth(qMax(w, qRound(sz.width() * 1.5)));
- if (sz.height() < h)
- sz.setHeight(qMax(h, qRound(sz.height() * 1.5)));
-
- // wasting too much space?
- if (sz.width() * sz.height() > w * h * 2.5)
- sz = QSize(w, h);
-
- delete textureBufferStack.at(currentTextureBuffer).fbo;
- textureBufferStack[currentTextureBuffer] =
- createTextureBuffer(sz, textureBufferStack.at(currentTextureBuffer).engine);
- qDebug() << "Creating new pixmap texture buffer:" << sz;
- }
- }
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setSamples(4);
+ format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB));
- if (textureBufferStack.at(currentTextureBuffer).fbo->isValid()) {
- m_renderFbo = textureBufferStack.at(currentTextureBuffer).fbo;
- m_engine = textureBufferStack.at(currentTextureBuffer).engine;
-
- ++currentTextureBuffer;
+ m_renderFbo = qgl_fbo_pool()->acquire(size(), format);
+ if (m_renderFbo) {
+ if (!m_engine)
+ m_engine = new QGL2PaintEngineEx;
return m_engine;
}
@@ -476,29 +594,37 @@ QPaintEngine* QGLPixmapData::paintEngine() const
return m_source.paintEngine();
}
+extern QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format);
+
+// If copyBack is true, bind will copy the contents of the render
+// FBO to the texture (which is not bound to the texture, as it's
+// a multisample FBO).
GLuint QGLPixmapData::bind(bool copyBack) const
{
if (m_renderFbo && copyBack) {
copyBackFromRenderFbo(true);
} else {
- if (m_hasFillColor) {
- m_dirty = true;
- m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
- m_source.fill(PREMUL(m_fillColor.rgba()));
- m_hasFillColor = false;
- }
ensureCreated();
}
GLuint id = m_texture.id;
glBindTexture(GL_TEXTURE_2D, id);
- return id;
-}
-GLuint QGLPixmapData::textureId() const
-{
- ensureCreated();
- return m_texture.id;
+ if (m_hasFillColor) {
+ if (!useFramebufferObjects()) {
+ m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
+ m_source.fill(PREMUL(m_fillColor.rgba()));
+ }
+
+ m_hasFillColor = false;
+
+ GLenum format = qt_gl_preferredTextureFormat();
+ QImage tx(w, h, QImage::Format_ARGB32_Premultiplied);
+ tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format));
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.bits());
+ }
+
+ return id;
}
QGLTexture* QGLPixmapData::texture() const
@@ -539,4 +665,9 @@ int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
}
}
+QGLPaintDevice *QGLPixmapData::glDevice() const
+{
+ return &m_glDevice;
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index 7a5e1970e..8a13e0311 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -57,11 +57,43 @@
#include "qgl.h"
#include "private/qpixmapdata_p.h"
+#include "private/qglpaintdevice_p.h"
QT_BEGIN_NAMESPACE
class QPaintEngine;
class QGLFramebufferObject;
+class QGLFramebufferObjectFormat;
+class QGLPixmapData;
+
+class QGLFramebufferObjectPool
+{
+public:
+ QGLFramebufferObject *acquire(const QSize &size, const QGLFramebufferObjectFormat &format, bool strictSize = false);
+ void release(QGLFramebufferObject *fbo);
+
+private:
+ QList<QGLFramebufferObject *> m_fbos;
+};
+
+QGLFramebufferObjectPool* qgl_fbo_pool();
+
+
+class QGLPixmapGLPaintDevice : public QGLPaintDevice
+{
+public:
+ QPaintEngine* paintEngine() const;
+
+ void beginPaint();
+ void endPaint();
+ QGLContext* context() const;
+ QSize size() const;
+
+ void setPixmapData(QGLPixmapData*);
+private:
+ QGLPixmapData *data;
+};
+
class QGLPixmapData : public QPixmapData
{
@@ -69,25 +101,29 @@ public:
QGLPixmapData(PixelType type);
~QGLPixmapData();
- bool isValid() const;
+ QPixmapData *createCompatiblePixmapData() const;
+ // Re-implemented from QPixmapData:
void resize(int width, int height);
- void fromImage(const QImage &image,
- Qt::ImageConversionFlags flags);
+ void fromImage(const QImage &image, Qt::ImageConversionFlags flags);
void copy(const QPixmapData *data, const QRect &rect);
-
bool scroll(int dx, int dy, const QRect &rect);
-
void fill(const QColor &color);
bool hasAlphaChannel() const;
QImage toImage() const;
QPaintEngine *paintEngine() const;
+ int metric(QPaintDevice::PaintDeviceMetric metric) const;
+
+ // For accessing as a target:
+ QGLPaintDevice *glDevice() const;
+ // For accessing as a source:
+ bool isValidContext(const QGLContext *ctx) const;
GLuint bind(bool copyBack = true) const;
- GLuint textureId() const;
QGLTexture *texture() const;
- bool isValidContext(const QGLContext *ctx) const;
+private:
+ bool isValid() const;
void ensureCreated() const;
@@ -96,22 +132,13 @@ public:
bool needsFill() const { return m_hasFillColor; }
QColor fillColor() const { return m_fillColor; }
- QSize size() const { return QSize(w, h); }
-
- QGLFramebufferObject *fbo() const;
-
- void makeCurrent();
- void doneCurrent();
- void swapBuffers();
-protected:
- int metric(QPaintDevice::PaintDeviceMetric metric) const;
-private:
QGLPixmapData(const QGLPixmapData &other);
QGLPixmapData &operator=(const QGLPixmapData &other);
void copyBackFromRenderFbo(bool keepCurrentFboBound) const;
+ QSize size() const { return QSize(w, h); }
static bool useFramebufferObjects();
@@ -132,6 +159,10 @@ private:
mutable bool m_hasFillColor;
mutable bool m_hasAlpha;
+
+ mutable QGLPixmapGLPaintDevice m_glDevice;
+
+ friend class QGLPixmapGLPaintDevice;
};
QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_x11gl_egl.cpp b/src/opengl/qpixmapdata_x11gl_egl.cpp
new file mode 100644
index 000000000..813e6c89a
--- /dev/null
+++ b/src/opengl/qpixmapdata_x11gl_egl.cpp
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qgl_p.h>
+#include <private/qegl_p.h>
+#include <private/qeglproperties_p.h>
+#include <private/qpaintengineex_opengl2_p.h>
+
+#include "qpixmapdata_x11gl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+extern EGLConfig qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly); // in qgl_x11egl.cpp
+extern bool qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly); // in qgl_x11egl.cpp
+
+// On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need
+// different contexts:
+static EGLContext qPixmapARGBSharedEglContext = EGL_NO_CONTEXT;
+static EGLContext qPixmapRGBSharedEglContext = EGL_NO_CONTEXT;
+
+bool QX11GLPixmapData::hasX11GLPixmaps()
+{
+ static bool checkedForX11Pixmaps = false;
+ static bool haveX11Pixmaps = false;
+
+ if (checkedForX11Pixmaps)
+ return haveX11Pixmaps;
+
+ checkedForX11Pixmaps = true;
+
+ QX11PixmapData *argbPixmapData = 0;
+ QX11PixmapData *rgbPixmapData = 0;
+ do {
+ if (qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty())
+ break;
+
+ // Check we actually have EGL configs which support pixmaps
+ EGLConfig argbConfig = qt_chooseEGLConfigForPixmap(true, false);
+ EGLConfig rgbConfig = qt_chooseEGLConfigForPixmap(false, false);
+
+ if (argbConfig == 0 || rgbConfig == 0)
+ break;
+
+ // Create the shared contexts:
+ eglBindAPI(EGL_OPENGL_ES_API);
+ EGLint contextAttribs[] = {
+#if defined(QT_OPENGL_ES_2)
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+#endif
+ EGL_NONE
+ };
+ qPixmapARGBSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0),
+ argbConfig, 0, contextAttribs);
+
+ if (argbConfig == rgbConfig) {
+ // If the configs are the same, we can re-use the same context.
+ qPixmapRGBSharedEglContext = qPixmapARGBSharedEglContext;
+ } else {
+ qPixmapRGBSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0),
+ rgbConfig, 0, contextAttribs);
+ }
+
+ argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType);
+ argbPixmapData->resize(100, 100);
+ argbPixmapData->fill(Qt::transparent); // Force ARGB
+
+ if (!qt_createEGLSurfaceForPixmap(argbPixmapData, false))
+ break;
+
+ haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0),
+ (EGLSurface)argbPixmapData->gl_surface,
+ (EGLSurface)argbPixmapData->gl_surface,
+ qPixmapARGBSharedEglContext);
+ if (!haveX11Pixmaps) {
+ EGLint err = eglGetError();
+ qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err);
+ break;
+ }
+
+ // If the ARGB & RGB configs are the same, we don't need to check RGB too
+ if (haveX11Pixmaps && (argbConfig != rgbConfig)) {
+ rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType);
+ rgbPixmapData->resize(100, 100);
+ rgbPixmapData->fill(Qt::red);
+
+ // Try to actually create an EGL pixmap surface
+ if (!qt_createEGLSurfaceForPixmap(rgbPixmapData, false))
+ break;
+
+ haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0),
+ (EGLSurface)rgbPixmapData->gl_surface,
+ (EGLSurface)rgbPixmapData->gl_surface,
+ qPixmapRGBSharedEglContext);
+ if (!haveX11Pixmaps) {
+ EGLint err = eglGetError();
+ qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err);
+ break;
+ }
+ }
+ } while (0);
+
+ if (qPixmapARGBSharedEglContext || qPixmapRGBSharedEglContext) {
+ eglMakeCurrent(QEglContext::defaultDisplay(0),
+ EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ }
+
+ if (argbPixmapData) {
+ if (argbPixmapData->gl_surface)
+ QGLContextPrivate::destroyGlSurfaceForPixmap(argbPixmapData);
+ delete argbPixmapData;
+ argbPixmapData = 0;
+ }
+ if (rgbPixmapData) {
+ if (rgbPixmapData->gl_surface)
+ QGLContextPrivate::destroyGlSurfaceForPixmap(rgbPixmapData);
+ delete rgbPixmapData;
+ rgbPixmapData = 0;
+ }
+
+ if (!haveX11Pixmaps) {
+ // Clean up the context(s) if we can't use X11GL pixmaps
+ if (qPixmapARGBSharedEglContext != EGL_NO_CONTEXT)
+ eglDestroyContext(QEglContext::defaultDisplay(0), qPixmapARGBSharedEglContext);
+
+ if (qPixmapRGBSharedEglContext != qPixmapARGBSharedEglContext &&
+ qPixmapRGBSharedEglContext != EGL_NO_CONTEXT)
+ {
+ eglDestroyContext(QEglContext::defaultDisplay(0), qPixmapRGBSharedEglContext);
+ }
+ qPixmapRGBSharedEglContext = EGL_NO_CONTEXT;
+ qPixmapARGBSharedEglContext = EGL_NO_CONTEXT;
+ }
+
+ if (haveX11Pixmaps)
+ qDebug("QX11GLPixmapData is supported");
+ else
+ qDebug("QX11GLPixmapData is *NOT* being used");
+
+ return haveX11Pixmaps;
+}
+
+QX11GLPixmapData::QX11GLPixmapData()
+ : QX11PixmapData(QPixmapData::PixmapType),
+ ctx(0)
+{
+}
+
+QX11GLPixmapData::~QX11GLPixmapData()
+{
+}
+
+static QGL2PaintEngineEx* qt_gl2_engine_for_pixmaps = 0;
+
+QPaintEngine* QX11GLPixmapData::paintEngine() const
+{
+ // We need to create the context before beginPaint - do it here:
+ if (!ctx) {
+ ctx = new QGLContext(glFormat());
+ if (ctx->d_func()->eglContext == 0)
+ ctx->d_func()->eglContext = new QEglContext();
+ ctx->d_func()->eglContext->openDisplay(0); // ;-)
+ ctx->d_func()->eglContext->setApi(QEgl::OpenGL);
+ ctx->d_func()->eglContext->setContext(hasAlphaChannel() ? qPixmapARGBSharedEglContext
+ : qPixmapRGBSharedEglContext);
+ }
+
+ if (!qt_gl2_engine_for_pixmaps)
+ qt_gl2_engine_for_pixmaps = new QGL2PaintEngineEx();
+
+ // Support multiple painters on multiple pixmaps simultaniously
+ if (qt_gl2_engine_for_pixmaps->isActive()) {
+ qWarning("Pixmap paint engine already active");
+ QPaintEngine* engine = new QGL2PaintEngineEx();
+ engine->setAutoDestruct(true);
+ return engine;
+ }
+
+ return qt_gl2_engine_for_pixmaps;
+}
+
+void QX11GLPixmapData::beginPaint()
+{
+// qDebug("QX11GLPixmapData::beginPaint()");
+ if ((EGLSurface)gl_surface == EGL_NO_SURFACE) {
+ qt_createEGLSurfaceForPixmap(this, false);
+ ctx->d_func()->eglSurface = (EGLSurface)gl_surface;
+ ctx->d_func()->valid = true; // ;-)
+ }
+ QGLPaintDevice::beginPaint();
+}
+
+void QX11GLPixmapData::endPaint()
+{
+ glFinish();
+ QGLPaintDevice::endPaint();
+}
+
+QGLContext* QX11GLPixmapData::context() const
+{
+ return ctx;
+}
+
+QSize QX11GLPixmapData::size() const
+{
+ return QSize(w, h);
+}
+
+
+QGLFormat QX11GLPixmapData::glFormat()
+{
+ return QGLFormat::defaultFormat(); //###
+}
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_x11gl_p.h b/src/opengl/qpixmapdata_x11gl_p.h
new file mode 100644
index 000000000..bba9bb380
--- /dev/null
+++ b/src/opengl/qpixmapdata_x11gl_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPIXMAPDATA_X11GL_P_H
+#define QPIXMAPDATA_X11GL_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 <private/qpixmapdata_p.h>
+#include <private/qpixmap_x11_p.h>
+#include <private/qglpaintdevice_p.h>
+
+#include <qgl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QX11GLPixmapData : public QX11PixmapData, public QGLPaintDevice
+{
+public:
+ QX11GLPixmapData();
+ virtual ~QX11GLPixmapData();
+
+ // Re-implemented from QGLPaintDevice
+ QPaintEngine* paintEngine() const; // Also re-implements QX11PixmapData::paintEngine
+ void beginPaint();
+ void endPaint();
+ QGLContext* context() const;
+ QSize size() const;
+
+ static bool hasX11GLPixmaps();
+ static QGLFormat glFormat();
+private:
+ mutable QGLContext* ctx;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QPIXMAPDATA_X11GL_P_H
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp
index 6d447d0e1..e353f5d4c 100644
--- a/src/opengl/qwindowsurface_gl.cpp
+++ b/src/opengl/qwindowsurface_gl.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -49,12 +49,12 @@
#include <qglpixelbuffer.h>
#include <qcolormap.h>
#include <qdesktopwidget.h>
+#include <private/qwidget_p.h>
#include "qdebug.h"
#ifdef Q_WS_X11
#include <private/qt_x11_p.h>
#include <qx11info_x11.h>
-#include <private/qwidget_p.h>
#ifndef QT_OPENGL_ES
#include <GL/glx.h>
@@ -71,6 +71,7 @@
#include <private/qgraphicssystem_gl_p.h>
#include <private/qpaintengineex_opengl2_p.h>
+#include <private/qpixmapdata_gl_p.h>
#ifndef QT_OPENGL_ES_2
#include <private/qpaintengine_opengl_p.h>
@@ -85,6 +86,10 @@
#include "qgl_cl_p.h"
#endif
+#ifdef QT_OPENGL_ES
+#include <private/qegl_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
//
@@ -190,6 +195,9 @@ public:
if (!initializing && !widget && !cleanedUp) {
initializing = true;
widget = new QGLWidget;
+ // We dont need this internal widget to appear in QApplication::topLevelWidgets()
+ if (QWidgetPrivate::allWidgets)
+ QWidgetPrivate::allWidgets->remove(widget);
initializing = false;
}
return widget;
@@ -229,6 +237,7 @@ QGLWidget* qt_gl_share_widget()
return _qt_gl_share_widget()->shareWidget();
}
+
struct QGLWindowSurfacePrivate
{
QGLFramebufferObject *fbo;
@@ -239,6 +248,7 @@ struct QGLWindowSurfacePrivate
int tried_fbo : 1;
int tried_pb : 1;
int destructive_swap_buffers : 1;
+ int geometry_updated : 1;
QGLContext *ctx;
@@ -248,10 +258,39 @@ struct QGLWindowSurfacePrivate
QSize size;
QList<QImage> buffers;
+ QGLWindowSurfaceGLPaintDevice glDevice;
+ QGLWindowSurface* q_ptr;
};
QGLFormat QGLWindowSurface::surfaceFormat;
+void QGLWindowSurfaceGLPaintDevice::endPaint()
+{
+ glFlush();
+ QGLPaintDevice::endPaint();
+}
+
+QSize QGLWindowSurfaceGLPaintDevice::size() const
+{
+ return d->size;
+}
+
+QGLContext* QGLWindowSurfaceGLPaintDevice::context() const
+{
+ return d->ctx;
+}
+
+
+int QGLWindowSurfaceGLPaintDevice::metric(PaintDeviceMetric m) const
+{
+ return qt_paint_device_metric(d->q_ptr->window(), m);
+}
+
+QPaintEngine *QGLWindowSurfaceGLPaintDevice::paintEngine() const
+{
+ return qt_qgl_paint_engine();
+}
+
QGLWindowSurface::QGLWindowSurface(QWidget *window)
: QWindowSurface(window), d_ptr(new QGLWindowSurfacePrivate)
{
@@ -260,9 +299,17 @@ QGLWindowSurface::QGLWindowSurface(QWidget *window)
d_ptr->pb = 0;
d_ptr->fbo = 0;
d_ptr->ctx = 0;
+#if defined (QT_OPENGL_ES_2)
+ d_ptr->tried_fbo = true;
+ d_ptr->tried_pb = true;
+#else
d_ptr->tried_fbo = false;
d_ptr->tried_pb = false;
+#endif
d_ptr->destructive_swap_buffers = qgetenv("QT_GL_SWAPBUFFER_PRESERVE").isNull();
+ d_ptr->glDevice.d = d_ptr;
+ d_ptr->q_ptr = this;
+ d_ptr->geometry_updated = false;
}
QGLWindowSurface::~QGLWindowSurface()
@@ -281,6 +328,10 @@ QGLWindowSurface::~QGLWindowSurface()
void QGLWindowSurface::deleted(QObject *object)
{
+ // Make sure that the fbo is destroyed before destroying its context.
+ delete d_ptr->fbo;
+ d_ptr->fbo = 0;
+
QWidget *widget = qobject_cast<QWidget *>(object);
if (widget) {
QWidgetPrivate *widgetPrivate = widget->d_func();
@@ -306,41 +357,30 @@ void QGLWindowSurface::hijackWindow(QWidget *widget)
QGLContext *ctx = new QGLContext(surfaceFormat, widget);
ctx->create(qt_gl_share_widget()->context());
-#ifdef Q_WS_MAC
- ctx->updatePaintDevice();
+
+#if defined(Q_WS_X11) && defined(QT_OPENGL_ES)
+ // Create the EGL surface to draw into. QGLContext::chooseContext()
+ // does not do this for X11/EGL, but does do it for other platforms.
+ // This probably belongs in qgl_x11egl.cpp.
+ QGLContextPrivate *ctxpriv = ctx->d_func();
+ ctxpriv->eglSurface = ctxpriv->eglContext->createSurface(widget);
+ if (ctxpriv->eglSurface == EGL_NO_SURFACE) {
+ qWarning() << "hijackWindow() could not create EGL surface";
+ }
+ qDebug("QGLWindowSurface - using EGLConfig %d", reinterpret_cast<int>(ctxpriv->eglContext->config()));
#endif
+
widgetPrivate->extraData()->glContext = ctx;
union { QGLContext **ctxPtr; void **voidPtr; };
- connect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(deleted(QObject *)));
+ connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(deleted(QObject*)));
voidPtr = &widgetPrivate->extraData()->glContext;
d_ptr->contexts << ctxPtr;
qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size();
}
-Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_window_surface_2_engine)
-
-#if !defined (QT_OPENGL_ES_2)
-Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_window_surface_engine)
-#endif
-
-/*! \reimp */
-QPaintEngine *QGLWindowSurface::paintEngine() const
-{
-#if !defined(QT_OPENGL_ES_2)
- if (!qt_gl_preferGL2Engine())
- return qt_gl_window_surface_engine();
-#endif
- return qt_gl_window_surface_2_engine();
-}
-
-int QGLWindowSurface::metric(PaintDeviceMetric m) const
-{
- return window()->metric(m);
-}
-
QGLContext *QGLWindowSurface::context() const
{
return d_ptr->ctx;
@@ -354,7 +394,7 @@ QPaintDevice *QGLWindowSurface::paintDevice()
return d_ptr->pb;
if (d_ptr->ctx)
- return this;
+ return &d_ptr->glDevice;
QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
ctx->makeCurrent();
@@ -365,7 +405,6 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize,
void QGLWindowSurface::beginPaint(const QRegion &)
{
- updateGeometry();
}
void QGLWindowSurface::endPaint(const QRegion &rgn)
@@ -378,12 +417,24 @@ void QGLWindowSurface::endPaint(const QRegion &rgn)
void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset)
{
+ if (context() && widget != window()) {
+ qWarning("No native child widget support in GL window surface without FBOs or pixel buffers");
+ return;
+ }
+
+ //### Find out why d_ptr->geometry_updated isn't always false.
+ // flush() should not be called when d_ptr->geometry_updated is true. It assumes that either
+ // d_ptr->fbo or d_ptr->pb is allocated and has the correct size.
+ if (d_ptr->geometry_updated)
+ return;
+
QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget();
Q_ASSERT(parent);
if (!geometry().isValid())
return;
+ // Needed to support native child-widgets...
hijackWindow(parent);
QRect br = rgn.boundingRect().translated(offset);
@@ -392,6 +443,7 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &
QRect rect = br.translated(-offset - wOffset);
const GLenum target = GL_TEXTURE_2D;
+ Q_UNUSED(target);
if (context()) {
context()->makeCurrent();
@@ -416,8 +468,6 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &
QRegion dirtyRegion = QRegion(window()->rect()) - d_ptr->paintedRegion;
if (!dirtyRegion.isEmpty()) {
- context()->makeCurrent();
-
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
@@ -452,56 +502,93 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &
return;
}
+ QGLContext *previous_ctx = const_cast<QGLContext *>(QGLContext::currentContext());
QGLContext *ctx = reinterpret_cast<QGLContext *>(parent->d_func()->extraData()->glContext);
- GLuint texture;
- if (d_ptr->fbo) {
- texture = d_ptr->fbo->texture();
- } else {
- d_ptr->pb->makeCurrent();
- glBindTexture(target, d_ptr->pb_tex_id);
- const uint bottom = window()->height() - (br.y() + br.height());
- glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height());
- texture = d_ptr->pb_tex_id;
- glBindTexture(target, 0);
+
+ // QPainter::end() should have unbound the fbo, otherwise something is very wrong...
+ Q_ASSERT(!d_ptr->fbo || !d_ptr->fbo->isBound());
+
+ if (ctx != previous_ctx) {
+ ctx->makeCurrent();
}
QSize size = widget->rect().size();
if (d_ptr->destructive_swap_buffers && ctx->format().doubleBuffer()) {
rect = parent->rect();
- br = rect.translated(wOffset);
+ br = rect.translated(wOffset + offset);
size = parent->size();
}
glDisable(GL_SCISSOR_TEST);
- if (d_ptr->fbo && QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit) {
+ if (d_ptr->fbo && (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)) {
const int h = d_ptr->fbo->height();
- const int x0 = rect.left();
- const int x1 = rect.left() + rect.width();
- const int y0 = h - (rect.top() + rect.height());
- const int y1 = h - rect.top();
+ const int sx0 = br.left();
+ const int sx1 = br.left() + br.width();
+ const int sy0 = h - (br.top() + br.height());
+ const int sy1 = h - br.top();
+
+ const int tx0 = rect.left();
+ const int tx1 = rect.left() + rect.width();
+ const int ty0 = parent->height() - (rect.top() + rect.height());
+ const int ty1 = parent->height() - rect.top();
+
+ if (window() == parent || d_ptr->fbo->format().samples() <= 1) {
+ // glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
+
+ glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
+ tx0, ty0, tx1, ty1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
+ } else {
+ // can't do sub-region blits with multisample FBOs
+ QGLFramebufferObject *temp = qgl_fbo_pool()->acquire(d_ptr->fbo->size(), QGLFramebufferObjectFormat());
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, temp->handle());
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
+
+ glBlitFramebufferEXT(0, 0, d_ptr->fbo->width(), d_ptr->fbo->height(),
+ 0, 0, d_ptr->fbo->width(), d_ptr->fbo->height(),
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, temp->handle());
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
- glBlitFramebufferEXT(x0, y0, x1, y1,
- x0, y0, x1, y1,
- GL_COLOR_BUFFER_BIT,
- GL_NEAREST);
+ glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
+ tx0, ty0, tx1, ty1,
+ GL_COLOR_BUFFER_BIT,
+ GL_NEAREST);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, d_ptr->fbo->handle());
+ glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
+
+ qgl_fbo_pool()->release(temp);
+ }
}
#if !defined(QT_OPENGL_ES_2)
else {
+ GLuint texture;
+ if (d_ptr->fbo) {
+ texture = d_ptr->fbo->texture();
+ } else {
+ d_ptr->pb->makeCurrent();
+ glBindTexture(target, d_ptr->pb_tex_id);
+ const uint bottom = window()->height() - (br.y() + br.height());
+ glCopyTexSubImage2D(target, 0, br.x(), bottom, br.x(), bottom, br.width(), br.height());
+ texture = d_ptr->pb_tex_id;
+ glBindTexture(target, 0);
+ }
+
glDisable(GL_DEPTH_TEST);
if (d_ptr->fbo) {
d_ptr->fbo->release();
} else {
ctx->makeCurrent();
-#ifdef Q_WS_MAC
- ctx->updatePaintDevice();
-#endif
}
glMatrixMode(GL_MODELVIEW);
@@ -522,6 +609,44 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &
if (d_ptr->fbo)
d_ptr->fbo->bind();
}
+#else
+ // OpenGL/ES 2.0 version of the fbo blit.
+ else if (d_ptr->fbo) {
+ Q_UNUSED(target);
+
+ GLuint texture = d_ptr->fbo->texture();
+
+ glDisable(GL_DEPTH_TEST);
+
+ if (d_ptr->fbo->isBound())
+ d_ptr->fbo->release();
+
+ glViewport(0, 0, size.width(), size.height());
+
+ QGLShaderProgram *blitProgram =
+ QGLEngineSharedShaders::shadersForContext(ctx)->blitProgram();
+ blitProgram->bind();
+ blitProgram->setUniformValue("imageTexture", 0 /*QT_IMAGE_TEXTURE_UNIT*/);
+
+ // The shader manager's blit program does not multiply the
+ // vertices by the pmv matrix, so we need to do the effect
+ // of the orthographic projection here ourselves.
+ QRectF r;
+ qreal w = size.width() ? size.width() : 1.0f;
+ qreal h = size.height() ? size.height() : 1.0f;
+ r.setLeft((rect.left() / w) * 2.0f - 1.0f);
+ if (rect.right() == (size.width() - 1))
+ r.setRight(1.0f);
+ else
+ r.setRight((rect.right() / w) * 2.0f - 1.0f);
+ r.setBottom((rect.top() / h) * 2.0f - 1.0f);
+ if (rect.bottom() == (size.height() - 1))
+ r.setTop(1.0f);
+ else
+ r.setTop((rect.bottom() / w) * 2.0f - 1.0f);
+
+ drawTexture(r, texture, window()->size(), br);
+ }
#endif
if (ctx->format().doubleBuffer())
@@ -530,9 +655,27 @@ void QGLWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &
glFlush();
}
-void QGLWindowSurface::updateGeometry()
+
+void QGLWindowSurface::setGeometry(const QRect &rect)
{
- QRect rect = QWindowSurface::geometry();
+ QWindowSurface::setGeometry(rect);
+ d_ptr->geometry_updated = true;
+}
+
+
+void QGLWindowSurface::updateGeometry() {
+ if (!d_ptr->geometry_updated)
+ return;
+ d_ptr->geometry_updated = false;
+
+
+ QRect rect = geometry();
+ hijackWindow(window());
+ QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
+
+#ifdef Q_WS_MAC
+ ctx->updatePaintDevice();
+#endif
const GLenum target = GL_TEXTURE_2D;
@@ -555,28 +698,24 @@ void QGLWindowSurface::updateGeometry()
if (d_ptr->destructive_swap_buffers
&& (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject)
-#ifdef QT_OPENGL_ES_2
- && (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)
-#endif
- && (d_ptr->fbo || !d_ptr->tried_fbo))
+ && (d_ptr->fbo || !d_ptr->tried_fbo)
+ && qt_gl_preferGL2Engine())
{
d_ptr->tried_fbo = true;
- hijackWindow(window());
- QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
ctx->d_ptr->internal_context = true;
ctx->makeCurrent();
delete d_ptr->fbo;
QGLFramebufferObjectFormat format;
format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
- format.setInternalFormat(GL_RGBA);
+ format.setInternalTextureFormat(GLenum(GL_RGBA));
format.setTextureTarget(target);
if (QGLExtensions::glExtensions & QGLExtensions::FramebufferBlit)
format.setSamples(8);
d_ptr->fbo = new QGLFramebufferObject(rect.size(), format);
- d_ptr->fbo->bind();
+
if (d_ptr->fbo->isValid()) {
qDebug() << "Created Window Surface FBO" << rect.size()
<< "with samples" << d_ptr->fbo->format().samples();
@@ -633,8 +772,6 @@ void QGLWindowSurface::updateGeometry()
}
#endif // !defined(QT_OPENGL_ES_2)
- hijackWindow(window());
- QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
ctx->makeCurrent();
if (d_ptr->destructive_swap_buffers) {
@@ -652,11 +789,6 @@ void QGLWindowSurface::updateGeometry()
d_ptr->ctx->d_ptr->internal_context = true;
}
-void QGLWindowSurface::setGeometry(const QRect &rect)
-{
- QWindowSurface::setGeometry(rect);
-}
-
bool QGLWindowSurface::scroll(const QRegion &area, int dx, int dy)
{
// this code randomly fails currently for unknown reasons
@@ -733,10 +865,23 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize,
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-#endif
glDisable(target);
glBindTexture(target, 0);
+#else
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray);
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, texCoordArray);
+
+ glBindTexture(target, tex_id);
+
+ glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
+ glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
+
+ glBindTexture(target, 0);
+#endif
}
QImage *QGLWindowSurface::buffer(const QWidget *widget)
diff --git a/src/opengl/qwindowsurface_gl_p.h b/src/opengl/qwindowsurface_gl_p.h
index f895203a2..5a9f38cab 100644
--- a/src/opengl/qwindowsurface_gl_p.h
+++ b/src/opengl/qwindowsurface_gl_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -56,6 +56,7 @@
#include <qglobal.h>
#include <qgl.h>
#include <private/qwindowsurface_p.h>
+#include <private/qglpaintdevice_p.h>
QT_BEGIN_NAMESPACE
@@ -65,7 +66,18 @@ class QRegion;
class QWidget;
struct QGLWindowSurfacePrivate;
-class QGLWindowSurface : public QObject, public QWindowSurface, public QPaintDevice
+class QGLWindowSurfaceGLPaintDevice : public QGLPaintDevice
+{
+public:
+ QPaintEngine* paintEngine() const;
+ void endPaint();
+ QSize size() const;
+ int metric(PaintDeviceMetric m) const;
+ QGLContext* context() const;
+ QGLWindowSurfacePrivate* d;
+};
+
+class QGLWindowSurface : public QObject, public QWindowSurface // , public QPaintDevice
{
Q_OBJECT
public:
@@ -87,11 +99,6 @@ public:
static QGLFormat surfaceFormat;
- QPaintEngine *paintEngine() const;
-
-protected:
- int metric(PaintDeviceMetric metric) const;
-
private slots:
void deleted(QObject *object);
diff --git a/src/opengl/qwindowsurface_x11gl.cpp b/src/opengl/qwindowsurface_x11gl.cpp
new file mode 100644
index 000000000..db81be26f
--- /dev/null
+++ b/src/opengl/qwindowsurface_x11gl.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QTime>
+#include <QDebug>
+
+#include <private/qt_x11_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
+
+#include "qwindowsurface_x11gl_p.h"
+#include "qpixmapdata_x11gl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QX11GLWindowSurface::QX11GLWindowSurface(QWidget* window)
+ : QWindowSurface(window), m_GC(0), m_window(window)
+{
+}
+
+QX11GLWindowSurface::~QX11GLWindowSurface()
+{
+ if (m_GC)
+ XFree(m_GC);
+}
+
+QPaintDevice *QX11GLWindowSurface::paintDevice()
+{
+ return &m_backBuffer;
+}
+
+extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp
+
+void QX11GLWindowSurface::flush(QWidget *widget, const QRegion &widgetRegion, const QPoint &offset)
+{
+// qDebug("QX11GLWindowSurface::flush()");
+ QTime startTime = QTime::currentTime();
+ if (m_backBuffer.isNull()) {
+ qDebug("QHarmattanWindowSurface::flush() - backBuffer is null, not flushing anything");
+ return;
+ }
+
+ QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft();
+ QRegion windowRegion(widgetRegion);
+ QRect boundingRect = widgetRegion.boundingRect();
+ if (!widgetOffset.isNull())
+ windowRegion.translate(-widgetOffset);
+ QRect windowBoundingRect = windowRegion.boundingRect();
+
+ int rectCount;
+ XRectangle *rects = (XRectangle *)qt_getClipRects(windowRegion, rectCount);
+ if (rectCount <= 0)
+ return;
+// qDebug() << "XSetClipRectangles";
+// for (int i = 0; i < num; ++i)
+// qDebug() << ' ' << i << rects[i].x << rects[i].x << rects[i].y << rects[i].width << rects[i].height;
+
+ if (m_GC == 0) {
+ m_GC = XCreateGC(X11->display, m_window->handle(), 0, 0);
+ XSetGraphicsExposures(X11->display, m_GC, False);
+ }
+
+ XSetClipRectangles(X11->display, m_GC, 0, 0, rects, rectCount, YXBanded);
+ XCopyArea(X11->display, m_backBuffer.handle(), m_window->handle(), m_GC,
+ boundingRect.x() + offset.x(), boundingRect.y() + offset.y(),
+ boundingRect.width(), boundingRect.height(),
+ windowBoundingRect.x(), windowBoundingRect.y());
+}
+
+void QX11GLWindowSurface::setGeometry(const QRect &rect)
+{
+ if (rect.width() > m_backBuffer.size().width() || rect.height() > m_backBuffer.size().height()) {
+ QSize newSize = rect.size();
+// QSize newSize(1024,512);
+ qDebug() << "QX11GLWindowSurface::setGeometry() - creating a pixmap of size" << newSize;
+ QX11GLPixmapData *pd = new QX11GLPixmapData;
+ pd->resize(newSize.width(), newSize.height());
+ m_backBuffer = QPixmap(pd);
+ }
+
+// if (gc)
+// XFreeGC(X11->display, gc);
+// gc = XCreateGC(X11->display, d_ptr->device.handle(), 0, 0);
+// XSetGraphicsExposures(X11->display, gc, False);
+ QWindowSurface::setGeometry(rect);
+}
+
+bool QX11GLWindowSurface::scroll(const QRegion &area, int dx, int dy)
+{
+ Q_UNUSED(area);
+ Q_UNUSED(dx);
+ Q_UNUSED(dy);
+ return false;
+}
+
+/*
+void QX11GLWindowSurface::beginPaint(const QRegion &region)
+{
+}
+
+void QX11GLWindowSurface::endPaint(const QRegion &region)
+{
+}
+
+QImage *QX11GLWindowSurface::buffer(const QWidget *widget)
+{
+}
+*/
+
+QT_END_NAMESPACE
diff --git a/src/opengl/qwindowsurface_x11gl_p.h b/src/opengl/qwindowsurface_x11gl_p.h
new file mode 100644
index 000000000..5ba4dc542
--- /dev/null
+++ b/src/opengl/qwindowsurface_x11gl_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSURFACE_X11GL_P_H
+#define QWINDOWSURFACE_X11GL_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 <private/qwindowsurface_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QX11GLWindowSurface : public QWindowSurface
+{
+public:
+ QX11GLWindowSurface(QWidget* window);
+ virtual ~QX11GLWindowSurface();
+
+ // Inherreted from QWindowSurface
+ QPaintDevice *paintDevice();
+ void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
+ void setGeometry(const QRect &rect);
+ bool scroll(const QRegion &area, int dx, int dy);
+
+private:
+ GC m_GC;
+ QPixmap m_backBuffer;
+ QWidget *m_window;
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSURFACE_X11GL_P_H
diff --git a/src/opengl/util/composition_mode_colorburn.glsl b/src/opengl/util/composition_mode_colorburn.glsl
index a5a153f89..c913b9737 100644
--- a/src/opengl/util/composition_mode_colorburn.glsl
+++ b/src/opengl/util/composition_mode_colorburn.glsl
@@ -5,8 +5,8 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = mix(src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
- src.a * (src.rgb * dst.a + dst.rgb * src.a - src.a * dst.a) / max(src.rgb, 0.00001) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
+ 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
index c19444169..b75e83cf4 100644
--- a/src/opengl/util/composition_mode_colordodge.glsl
+++ b/src/opengl/util/composition_mode_colordodge.glsl
@@ -5,8 +5,8 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- vec3 temp = src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
- result.rgb = mix(dst.rgb * src.a / max(1 - src.rgb / max(src.a, 0.000001), 0.000001) + temp,
+ 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));
diff --git a/src/opengl/util/composition_mode_darken.glsl b/src/opengl/util/composition_mode_darken.glsl
index c1e83fd9e..8bbb82b3c 100644
--- a/src/opengl/util/composition_mode_darken.glsl
+++ b/src/opengl/util/composition_mode_darken.glsl
@@ -3,7 +3,7 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = min(src.rgb * dst.a, dst.rgb * src.a) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
+ 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
index ca13ce70a..3c46ec71f 100644
--- a/src/opengl/util/composition_mode_difference.glsl
+++ b/src/opengl/util/composition_mode_difference.glsl
@@ -3,7 +3,7 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = src.rgb + dst.rgb - 2 * min(src.rgb * dst.a, dst.rgb * src.a);
+ 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
index ccd118309..59c2da99e 100644
--- a/src/opengl/util/composition_mode_exclusion.glsl
+++ b/src/opengl/util/composition_mode_exclusion.glsl
@@ -3,7 +3,7 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = (src.rgb * dst.a + dst.rgb * src.a - 2 * src.rgb * dst.rgb) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
+ 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
index 9dd4de3cd..4ea355029 100644
--- a/src/opengl/util/composition_mode_hardlight.glsl
+++ b/src/opengl/util/composition_mode_hardlight.glsl
@@ -5,9 +5,9 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = mix(2 * src.rgb * dst.rgb + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
- src.a * dst.a - 2 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
- step(src.a, 2 * src.rgb));
+ 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
index 1fbd27a04..13ef507a4 100644
--- a/src/opengl/util/composition_mode_lighten.glsl
+++ b/src/opengl/util/composition_mode_lighten.glsl
@@ -3,7 +3,7 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = max(src.rgb * dst.a, dst.rgb * src.a) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
+ 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
index 268345a87..f90b7f00a 100644
--- a/src/opengl/util/composition_mode_multiply.glsl
+++ b/src/opengl/util/composition_mode_multiply.glsl
@@ -3,7 +3,7 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = src.rgb * dst.rgb + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
+ 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
index a9b72267a..f621bdee9 100644
--- a/src/opengl/util/composition_mode_overlay.glsl
+++ b/src/opengl/util/composition_mode_overlay.glsl
@@ -5,9 +5,9 @@
vec4 composite(vec4 src, vec4 dst)
{
vec4 result;
- result.rgb = mix(2 * src.rgb * dst.rgb + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
- src.a * dst.a - 2 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a),
- step(dst.a, 2 * dst.rgb));
+ 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_softlight.glsl b/src/opengl/util/composition_mode_softlight.glsl
index 0237827ca..e4c1f8915 100644
--- a/src/opengl/util/composition_mode_softlight.glsl
+++ b/src/opengl/util/composition_mode_softlight.glsl
@@ -1,18 +1,22 @@
-// Dca' = 2.Sca < Sa ?
-// Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) :
-// (8.Dca <= Da ?
-// Dca.(Sa - (1 - Dca/Da).(2.Sca - Sa).(3 - 8.Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) :
-// (Dca.Sa + ((Dca/Da)^(0.5).Da - Dca).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa))
+// 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);
- result.rgb = mix(dst.rgb * (src.a - (1 - dst.rgb / da) * (2 * src.rgb - src.a)),
- mix(dst.rgb * (src.a - (1 - dst.rgb / da) * (2 * src.rgb - src.a) * (3 - 8 * dst.rgb / da)),
- (dst.rgb * src.a + (sqrt(dst.rgb / da) * dst.a - dst.rgb) * (2 * src.rgb - src.a)),
- step(dst.a, 8 * dst.rgb)),
- step(src.a, 2 * src.rgb)) + src.rgb * (1 - dst.a) + dst.rgb * (1 - src.a);
+ 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/conical_brush.glsl b/src/opengl/util/conical_brush.glsl
index 83ee2f5b6..b3ec1d7ef 100644
--- a/src/opengl/util/conical_brush.glsl
+++ b/src/opengl/util/conical_brush.glsl
@@ -20,7 +20,7 @@ vec4 brush()
/* 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 = (atan2(-A.y, A.x) + angle) / (2.0 * M_PI);
+ 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.glsl b/src/opengl/util/ellipse.glsl
deleted file mode 100644
index 860ae77e6..000000000
--- a/src/opengl/util/ellipse.glsl
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "ellipse_functions.glsl"
-
-void main()
-{
- gl_FragColor = ellipse();
-}
diff --git a/src/opengl/util/ellipse_aa.glsl b/src/opengl/util/ellipse_aa.glsl
index f7a6454ae..257e3bbd4 100644
--- a/src/opengl/util/ellipse_aa.glsl
+++ b/src/opengl/util/ellipse_aa.glsl
@@ -1,6 +1,58 @@
-#include "ellipse_functions.glsl"
+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();
+ gl_FragColor = ellipse_aa().xxxx;
}
diff --git a/src/opengl/util/ellipse_aa_copy.glsl b/src/opengl/util/ellipse_aa_copy.glsl
deleted file mode 100644
index 5372f585e..000000000
--- a/src/opengl/util/ellipse_aa_copy.glsl
+++ /dev/null
@@ -1,11 +0,0 @@
-uniform vec2 r; // r_x and r_y
-
-uniform sampler2D texture;
-uniform vec2 inv_texture_size;
-
-#include "ellipse_functions.glsl"
-
-void main()
-{
- gl_FragColor = ellipse_aa() * texture2D(texture, gl_FragCoord.xy * inv_texture_size);
-}
diff --git a/src/opengl/util/ellipse_aa_radial.glsl b/src/opengl/util/ellipse_aa_radial.glsl
deleted file mode 100644
index 0878f9997..000000000
--- a/src/opengl/util/ellipse_aa_radial.glsl
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "ellipse_functions.glsl"
-
-uniform sampler1D palette;
-uniform vec2 fmp;
-uniform float fmp2_m_radius2;
-uniform vec4 inv_matrix;
-uniform vec2 inv_matrix_offset;
-
-void main()
-{
- // float2 A = frag_coord.xy;//mul(inv_matrix, frag_coord.xy) + inv_matrix_offset;
- mat2 mat;
- mat[0][0] = inv_matrix.x;
- mat[0][1] = inv_matrix.y;
- mat[1][0] = inv_matrix.z;
- mat[1][1] = inv_matrix.w;
- vec2 A = gl_FragCoord.xy * mat + inv_matrix_offset;
- 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);
- gl_FragColor = texture1D(palette, val) * ellipse_aa();
-}
diff --git a/src/opengl/util/ellipse_functions.glsl b/src/opengl/util/ellipse_functions.glsl
deleted file mode 100644
index eed18e858..000000000
--- a/src/opengl/util/ellipse_functions.glsl
+++ /dev/null
@@ -1,63 +0,0 @@
-uniform vec3 inv_matrix_m0;
-uniform vec3 inv_matrix_m1;
-uniform vec3 inv_matrix_m2;
-
-uniform vec2 ellipse_offset;
-
-float ellipse()
-{
- vec2 st = gl_TexCoord[0].st;
-
- if (dot(st, st) > 1)
- discard;
-
- return 1.0;
-}
-
-// 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)));
-}
diff --git a/src/opengl/util/fragmentprograms_p.h b/src/opengl/util/fragmentprograms_p.h
index 9451eda2f..224105736 100644
--- a/src/opengl/util/fragmentprograms_p.h
+++ b/src/opengl/util/fragmentprograms_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,26 +21,26 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
-#ifndef FRAGMENTPROGRAMS_H
-#define FRAGMENTPROGRAMS_H
+
+#ifndef FRAGMENTPROGRAMS_P_H
+#define FRAGMENTPROGRAMS_P_H
//
// W A R N I N G
@@ -131,58 +132,57 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA =
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "ADD R4.x, fragment.position, c[0];\n"
+ "ADD R3.z, fragment.position.x, c[0].x;\n"
"ADD R0.y, fragment.position, -c[0].x;\n"
- "MAX R2.x, R0.y, fragment.texcoord[0].y;\n"
+ "MAX R4.x, fragment.texcoord[0].y, R0.y;\n"
"ADD R0.x, fragment.position.y, c[0];\n"
- "MIN R2.y, R0.x, fragment.texcoord[0].x;\n"
- "ADD R3.x, fragment.position, -c[0];\n"
- "ADD R1.zw, -fragment.texcoord[0], -fragment.texcoord[0];\n"
- "MOV R3.y, R4.x;\n"
- "MOV R0.yw, R2.x;\n"
- "MOV R0.xz, R2.y;\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 R1.xy, fragment.position.x, c[0].y, -R0.zwzw;\n"
- "MOV R0.w, R1.x;\n"
- "MOV R1.x, R0.y;\n"
- "MOV R0.z, R0.x;\n"
- "SGE R2.zw, R1.xyxy, R0;\n"
- "MAX R0.xy, R0.zwzw, R1;\n"
- "MIN R0.zw, R0, R1.xyxy;\n"
- "MAD R2.zw, R2, R1, fragment.texcoord[0];\n"
- "ADD R1, R3.xyxy, -R0.zzww;\n"
- "MAD R1, R1, R2.zzww, R2.x;\n"
- "ADD R3.zw, R0.xyxy, R0;\n"
- "ADD R3.y, R2, -R2.x;\n"
- "ADD R2.zw, R1.xyyw, -R2.x;\n"
- "ADD R4.zw, R4.x, -R0;\n"
- "MUL R2.zw, R4, R2;\n"
- "ADD R4.zw, R1.xyyw, R1.xyxz;\n"
- "ADD R1.xz, R2.y, -R1;\n"
- "MAD R2.zw, -R2, c[0].x, R3.y;\n"
- "MAD R3.zw, R3, c[0].x, -R3.x;\n"
- "MAD R3.zw, R3, R3.y, -R2;\n"
- "ADD R1.y, R4.x, -R3.x;\n"
- "MAD R4.zw, -R4, c[0].x, R2.y;\n"
- "MUL R4.zw, R4, R1.y;\n"
- "ADD R1.yw, R0.xxzy, -R3.x;\n"
- "MUL R1.xy, R1.xzzw, R1.ywzw;\n"
- "MAD R1.zw, R1.xyxy, c[0].x, -R4;\n"
- "SGE R1.xy, R4.x, R0;\n"
- "MUL R1.zw, R1.xyxy, R1;\n"
- "MAD R1.xy, R1, R3.zwzw, R2.zwzw;\n"
- "SGE R2.zw, R3.x, R0;\n"
- "ADD R1.zw, R4, R1;\n"
- "ADD R1.zw, R1, -R1.xyxy;\n"
- "MAD R1.xy, R2.zwzw, R1.zwzw, R1;\n"
- "ADD R1.xy, R1, -R3.y;\n"
- "SGE R0.zw, R4.x, R0;\n"
- "MAD R0.zw, R0, R1.xyxy, R3.y;\n"
- "SGE R0.xy, R0, R3.x;\n"
- "MUL R0.xy, R0.zwzw, R0;\n"
- "ADD R0.x, R3.y, -R0;\n"
- "SGE R0.z, R2.y, R2.x;\n"
- "ADD R0.x, R0, -R0.y;\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"
;
@@ -195,32 +195,32 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_MASK_ELLIPSE_AA =
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R1.xyz, R0.y, c[2];\n"
- "MAD R0.xyz, R0.x, c[1], R1;\n"
- "ADD R0.xyz, R0, c[3];\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[1];\n"
- "MOV R1.zw, c[2].xyxy;\n"
- "MOV R0.x, c[1].z;\n"
- "MOV R0.y, c[2].z;\n"
- "MAD R0, -R0.xyxy, R0.zzww, R1.xzyw;\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, R0, R2.z;\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.xy, R1, R0.ywzw;\n"
- "ADD R0.w, R0.x, R0.y;\n"
- "MUL R0.xy, R2, R2;\n"
- "ADD R0.x, R0, R0.y;\n"
- "ADD R0.z, R1, R1.w;\n"
- "MUL R0.zw, R0, R0;\n"
+ "MUL R0.zw, R1.xyxy, R0.xyyw;\n"
"ADD R0.y, R0.z, R0.w;\n"
- "RSQ R0.y, R0.y;\n"
- "ADD R0.x, -R0, c[4].y;\n"
- "MAD_SAT R0.x, R0.y, R0, -c[4].z;\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"
@@ -230,36 +230,34 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_MASK_ELLIPSE_AA =
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SIMPLE_PORTER_DUFF =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 1 },\n"
- " program.local[5..6] };\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 R1, R0, texture[0], 2D;\n"
- "MUL R0.xyz, R1, c[6].y;\n"
- "MUL R2.xyz, R0, fragment.color.primary.w;\n"
- "MUL R0.xyz, fragment.color.primary, c[6].x;\n"
- "MAD R2.xyz, R0, R1.w, R2;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "ADD R0.w, -R1, c[4].x;\n"
- "MUL R0.xyz, fragment.color.primary, c[5].y;\n"
- "MAD R2.xyz, R0, R0.w, R2;\n"
- "MUL R0.xyz, R1, c[5].z;\n"
- "ADD R0.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R0, R0.w, R2;\n"
- "ADD R0.y, -R1.w, c[4].x;\n"
- "MUL R0.x, fragment.color.primary.w, R1.w;\n"
- "MUL R0.y, fragment.color.primary.w, R0;\n"
- "MUL R0.z, R1.w, R0.w;\n"
- "DP3 R2.w, R0, c[5];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -270,21 +268,21 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "ADD R0.x, -R1.w, c[4];\n"
- "MUL R0.xyz, fragment.color.primary, R0.x;\n"
- "MAD R0.xyz, fragment.color.primary, R1, R0;\n"
- "ADD R0.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R1, R0.w, R0;\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[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -294,16 +292,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "ADD R2, fragment.color.primary, R1;\n"
- "MUL R0.xy, R0, c[1];\n"
- "MAD R2, -fragment.color.primary, R1, R2;\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -315,7 +313,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xy, fragment.position, c[3];\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"
@@ -336,11 +334,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[3];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -352,23 +350,23 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R1, fragment.color.primary.w;\n"
- "MUL R0.xyz, fragment.color.primary, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "ADD R0.w, -R1, c[4].x;\n"
- "MAD R0.xyz, fragment.color.primary, R0.w, R0;\n"
- "ADD R0.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R1, R0.w, R0;\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[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -379,45 +377,45 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R1, fragment.color.primary.w;\n"
- "MUL R0.xyz, fragment.color.primary, R1.w;\n"
- "MAX R0.xyz, R0, R2;\n"
- "ADD R0.w, -R1, c[4].x;\n"
- "MAD R0.xyz, fragment.color.primary, R0.w, R0;\n"
- "ADD R0.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R1, R0.w, R0;\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[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "ADD R1.y, -fragment.color.primary.w, c[4].x;\n"
- "MAX R1.x, fragment.color.primary.w, c[4].y;\n"
- "MUL R2.xyz, R0, R1.y;\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.x, R1.x;\n"
- "MAD R1.xyz, -fragment.color.primary, R1.x, c[4].x;\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, R0, fragment.color.primary.w;\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"
@@ -430,11 +428,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"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[0];\n"
- "MUL R1.xy, R1, c[1];\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[2];\n"
+ "DP4 R1.x, R1, c[3];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -442,29 +440,28 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
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-06 } };\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[3];\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, R0, fragment.color.primary.w;\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"
- "ADD R2.w, -fragment.color.primary, c[4].x;\n"
"MUL R1.xyz, R0, R2.w;\n"
"MAD R1.xyz, fragment.color.primary, R1.w, R1;\n"
- "ADD R2.w, -fragment.color.primary, c[4].x;\n"
"MAD R3.xyz, R0, R2.w, R3;\n"
"MUL R1.w, fragment.color.primary, R0;\n"
"ADD R3.xyz, R3, -R1;\n"
@@ -472,11 +469,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"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[0];\n"
- "MUL R1.xy, R1, c[1];\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[2];\n"
+ "DP4 R1.x, R1, c[3];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -489,7 +486,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xy, fragment.position, c[3];\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"
@@ -510,11 +507,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[3];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -522,58 +519,57 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SOFTLIGHT =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..3],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 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[3];\n"
+ "MUL R0.xy, fragment.position, c[1];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MAX R1.x, R0.w, c[4].y;\n"
- "RCP R1.w, R1.x;\n"
- "MUL R2.xyz, R0, R1.w;\n"
- "MUL R1.xyz, -R2, c[4].w;\n"
- "RSQ R2.w, R2.x;\n"
- "ADD R4.xyz, R1, c[5].x;\n"
- "MAD R1.xyz, -R0, R1.w, c[4].x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "RCP R2.x, R2.w;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R5.xyz, R2, R0.w, -R0;\n"
- "MAD R2.xyz, fragment.color.primary, c[4].z, -fragment.color.primary.w;\n"
- "MUL R3.xyz, R1, R2;\n"
- "MAD R3.xyz, -R3, R4, fragment.color.primary.w;\n"
- "MUL R4.xyz, R5, R2;\n"
- "MAD R1.xyz, -R1, R2, fragment.color.primary.w;\n"
- "MAD R5.xyz, R0, fragment.color.primary.w, R4;\n"
- "MUL R3.xyz, R0, R3;\n"
- "MUL R4.xyz, R0, c[4].w;\n"
- "ADD R5.xyz, R5, -R3;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R4.xyz, R4, R5;\n"
- "ADD R2.xyz, R3, R4;\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"
- "MUL R3.xyz, fragment.color.primary, c[4].z;\n"
- "ADD R2.xyz, R2, -R1;\n"
- "SGE R3.xyz, R3, fragment.color.primary.w;\n"
- "MUL R2.xyz, R3, R2;\n"
- "ADD 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"
+ "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[0];\n"
- "MUL R1.xy, R1, c[1];\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[2];\n"
+ "DP4 R1.x, R1, c[3];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -586,77 +582,75 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R1, fragment.color.primary.w;\n"
- "MUL R0.xyz, fragment.color.primary, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "ADD R3.xyz, fragment.color.primary, R1;\n"
- "MAD R2.xyz, -R0, c[4].x, R3;\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[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xy, fragment.position, c[3];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MUL R0.xyz, R1, fragment.color.primary.w;\n"
- "MAD R2.xyz, fragment.color.primary, R1.w, R0;\n"
- "MUL R0.xyz, fragment.color.primary, R1;\n"
- "MAD R0.xyz, -R0, c[4].y, R2;\n"
- "ADD R0.w, -R1, c[4].x;\n"
- "MAD R0.xyz, fragment.color.primary, R0.w, R0;\n"
- "ADD R0.w, -fragment.color.primary, c[4].x;\n"
- "MAD R2.xyz, R1, R0.w, R0;\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[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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],\n"
- " { 1 },\n"
- " program.local[2..3] };\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[0];\n"
+ "MUL R0.xy, fragment.position, c[2];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R1.xyz, R0, c[3].y;\n"
- "MUL R2.xyz, R1, fragment.color.primary.w;\n"
- "MUL R1.xyz, fragment.color.primary, c[3].x;\n"
- "MAD R2.xyz, R1, R0.w, R2;\n"
- "MUL R0.xyz, R0, c[2].z;\n"
- "ADD R1.w, -R0, c[1].x;\n"
- "MUL R1.xyz, fragment.color.primary, c[2].y;\n"
- "MAD R1.xyz, R1, R1.w, R2;\n"
- "ADD R1.w, -fragment.color.primary, c[1].x;\n"
- "MAD result.color.xyz, R0, R1.w, R1;\n"
- "ADD R0.y, -R0.w, c[1].x;\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, R1.w;\n"
- "MUL R0.y, fragment.color.primary.w, R0;\n"
- "DP3 result.color.w, R0, c[2];\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"
;
@@ -732,7 +726,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R2;\n"
"MUL R0.xy, fragment.position, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, fragment.color.primary.w;\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"
@@ -753,7 +747,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R2;\n"
"MUL R0.xy, fragment.position, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, fragment.color.primary.w;\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"
@@ -768,7 +762,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_COLORDODGE_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[2] = { program.local[0],\n"
- " { 1, 1e-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -782,7 +776,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"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, R0, fragment.color.primary.w;\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"
@@ -801,7 +795,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
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-06 } };\n"
+ " { 1, 9.9999997e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -809,7 +803,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R4;\n"
"MUL R0.xy, fragment.position, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R1.xyz, R0, fragment.color.primary.w;\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"
@@ -822,7 +816,6 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"RCP R1.z, R1.z;\n"
"MAD R1.xyz, R3, R1, R4;\n"
"MUL R3.xyz, R0, R2.w;\n"
- "ADD R2.w, -fragment.color.primary, c[1].x;\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"
@@ -869,8 +862,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_SOFTLIGHT_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[3] = { program.local[0],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -879,43 +872,42 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"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].y;\n"
- "RCP R1.w, R1.x;\n"
- "MUL R2.xyz, R0, R1.w;\n"
- "MUL R1.xyz, -R2, c[1].w;\n"
- "ADD R4.xyz, R1, c[2].x;\n"
- "MAD R1.xyz, -R0, R1.w, c[1].x;\n"
- "RSQ R2.w, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "RCP R2.x, R2.w;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R5.xyz, R2, R0.w, -R0;\n"
- "MAD R2.xyz, fragment.color.primary, c[1].z, -fragment.color.primary.w;\n"
- "MUL R3.xyz, R1, R2;\n"
- "MAD R3.xyz, -R3, R4, fragment.color.primary.w;\n"
- "MUL R4.xyz, R5, R2;\n"
- "MAD R1.xyz, -R1, R2, fragment.color.primary.w;\n"
- "MAD R5.xyz, R0, fragment.color.primary.w, R4;\n"
- "MUL R3.xyz, R0, R3;\n"
- "MUL R4.xyz, R0, c[1].w;\n"
- "ADD R5.xyz, R5, -R3;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R4.xyz, R4, R5;\n"
- "ADD R2.xyz, R3, R4;\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"
- "MUL R3.xyz, fragment.color.primary, c[1].z;\n"
- "ADD R2.xyz, R2, -R1;\n"
- "SGE R3.xyz, R3, fragment.color.primary.w;\n"
- "MUL R2.xyz, R3, R2;\n"
- "ADD 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"
+ "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"
;
@@ -928,7 +920,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"TEMP R2;\n"
"MUL R0.xy, fragment.position, c[0];\n"
"TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, fragment.color.primary.w;\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"
@@ -941,20 +933,20 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODES_EXCLUSION_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[2] = { program.local[0],\n"
- " { 1, 2 } };\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, R0, fragment.color.primary.w;\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].y, R2;\n"
- "ADD R1.w, -R0, c[1].x;\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];\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"
@@ -964,8 +956,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
"!!ARBfp1.0\n"
"PARAM c[3] = { program.local[0..2] };\n"
"TEMP R0;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\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"
@@ -974,359 +966,351 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_SOLID_COMPOSITION_MODE_BLEND_MODE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[1] = { program.local[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..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..11] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.z, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[9].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, c[7].x;\n"
- "MUL R0.y, c[8].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, c[11].y;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[11].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "ADD R2.w, -R1, c[7].z;\n"
- "MUL R0.xyz, R0, c[10].y;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "MUL R0.xyz, R1, c[10].z;\n"
- "ADD R3.z, -R0.w, c[7];\n"
- "MAD R2.xyz, R0, R3.z, R2;\n"
- "MUL R0.y, R0.w, R2.w;\n"
- "MUL R0.x, R0.w, R1.w;\n"
- "MUL R0.z, R1.w, R3;\n"
- "DP3 R2.w, R0, c[10];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\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, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.z, R0.y;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[9].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, c[7].x;\n"
- "MUL R0.y, c[8].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, R0.y;\n"
- "TEX R0, R0, texture[2], 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, c[7].z;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..6],\n"
- " { 2, 4 },\n"
- " program.local[8..9] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\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, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2, R0, R1;\n"
- "MAD R2, -R0, R1, R2;\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\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, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\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"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\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 R2.w, -R1, c[7].z;\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].x;\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[7].z;\n"
- "MAD R3.xyz, R3, c[7].x, R4;\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[7].x;\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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\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..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\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, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\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, -R1, c[7].z;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].z;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\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, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\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, -R1, c[7].z;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].z;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..6],\n"
- " { 2, 4, 1, 1e-06 },\n"
- " program.local[8..9] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\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, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\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[7].w;\n"
+ "MAX R1.x, R0.w, c[9].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[9];\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[7].z;\n"
+ "ADD R2.w, -R0, c[9].z;\n"
"MUL R3.xyz, R1, R2.w;\n"
- "ADD R2.w, -R1, c[7].z;\n"
+ "ADD R2.w, -R1, c[9].z;\n"
"MAD R4.xyz, R0, R2.w, R3;\n"
- "MUL R3.xyz, R1, R0.w;\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"
@@ -1339,57 +1323,56 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\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..6],\n"
- " { 2, 4, 1, 9.9999997e-06 },\n"
- " program.local[8..9] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\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, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\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, R1, R0.w;\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[7].w;\n"
- "ADD R2.w, -R1, c[7].z;\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[7].z;\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"
@@ -1403,60 +1386,59 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\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..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\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, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\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"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\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 R2.w, -R1, c[7].z;\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].x;\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[7].z;\n"
- "MAD R3.xyz, R3, c[7].x, R4;\n"
- "MUL R0.xyz, R0, c[7].x;\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"
@@ -1464,21 +1446,20 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\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..6],\n"
- " { 2, 4, 1, 9.9999997e-06 },\n"
- " program.local[8..9],\n"
- " { 8, 3 } };\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"
@@ -1486,259 +1467,254 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\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, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.zw, fragment.position.xyxy, c[9].xyxy;\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"
- "MUL R0.x, R0, c[7];\n"
"MAD R0.y, R0.x, R0.x, -R0;\n"
- "MAX R0.z, R1.w, c[7].w;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "MUL R6.xyz, -R2, c[10].x;\n"
- "MAD R3.xyz, -R1, R2.w, c[7].z;\n"
"RSQ R0.y, R0.y;\n"
"RCP R0.y, R0.y;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "MOV R0.y, c[7].x;\n"
- "MUL R0.y, c[8].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, 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 R4.xyz, R0, c[7].x, -R0.w;\n"
- "MUL R5.xyz, R3, R4;\n"
- "MAD R3.xyz, -R3, R4, R0.w;\n"
- "ADD R6.xyz, R6, c[10].y;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MAD R5.xyz, -R5, R6, R0.w;\n"
- "MUL R3.xyz, R1, R3;\n"
- "ADD R2.w, -R1, c[7].z;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R1.w, -R1;\n"
- "MUL R6.xyz, R2, R4;\n"
- "MUL R2.xyz, R1, R5;\n"
- "MAD R6.xyz, R1, R0.w, R6;\n"
- "MUL R4.xyz, R0, c[7].x;\n"
- "MUL R5.xyz, R1, c[10].x;\n"
- "ADD R6.xyz, R6, -R2;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R2.xyz, R2, R5;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].z;\n"
- "MAD R2.xyz, R1, R2.x, R0;\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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\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..6],\n"
- " { 2, 4 },\n"
- " program.local[8..9] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.z, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[9].xyxy;\n"
- "MOV R0.y, c[7].x;\n"
- "MUL R0.y, c[8].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R3.xyz, R0, R1;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "MAD R2.xyz, -R0, c[7].x, R3;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..6],\n"
- " { 2, 4, 1 },\n"
- " program.local[8..9] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\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, c[8].x, -R0;\n"
- "MUL R0.y, R0.z, c[7];\n"
- "MUL R0.x, R0, c[7];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[7].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[8].x, R0;\n"
- "MUL R1.xy, fragment.position, c[9];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MAD R3.xyz, R0, R1.w, R2;\n"
- "MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[7].x, R3;\n"
- "ADD R2.w, -R1, c[7].z;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].z;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..8] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.z, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\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[8].y;\n"
- "MOV R0.y, c[4].x;\n"
- "MUL R0.y, c[5].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, R0.y;\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, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[8].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R2.w, -R1, c[4].z;\n"
- "MUL R0.xyz, R0, c[7].y;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[4].z;\n"
- "MUL R1.xyz, R1, c[7].z;\n"
- "MAD result.color.xyz, R1, R2.x, R0;\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[7];\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..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.z, R0.y;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\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.y, c[4].x;\n"
- "MUL R0.y, c[5].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, R0.y;\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[4].z;\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[4].z;\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"
@@ -1746,32 +1722,31 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SCREEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4 },\n"
- " program.local[5..6] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "RSQ R0.z, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "ADD R0.x, -R0, R0.z;\n"
- "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
- "MOV R0.y, c[4].x;\n"
- "MUL R0.y, c[5].x, R0;\n"
- "RCP R0.y, 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"
@@ -1782,50 +1757,49 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_OVERLAY_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\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"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\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"
- "ADD R2.w, -R1, c[4].z;\n"
- "MUL R2.xyz, R2, c[4].x;\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[4].z;\n"
- "MAD R0.xyz, R0, c[4].x, R3;\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[4].x;\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"
@@ -1836,43 +1810,42 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_DARKEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\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, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MIN R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4].z;\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[4].z;\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"
@@ -1880,43 +1853,42 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_LIGHTEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\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, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MAX R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4].z;\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[4].z;\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"
@@ -1924,45 +1896,44 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORDODGE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1, 1e-06 },\n"
- " program.local[5..6] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\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[4].w;\n"
+ "MAX R1.x, R0.w, c[6].w;\n"
"RCP R1.x, R1.x;\n"
- "MAD R1.xyz, -R0, R1.x, c[4].z;\n"
- "MAX R2.xyz, R1, c[4].w;\n"
- "MUL R1.xy, fragment.position, c[6];\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[4].z;\n"
+ "ADD R2.w, -R0, c[6].z;\n"
"MUL R3.xyz, R1, R2.w;\n"
- "ADD R2.w, -R1, c[4].z;\n"
+ "ADD R2.w, -R1, c[6].z;\n"
"MAD R3.xyz, R0, R2.w, R3;\n"
- "MUL R1.xyz, R1, R0.w;\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"
@@ -1980,46 +1951,45 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_COLORBURN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1, 9.9999997e-06 },\n"
- " program.local[5..6] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\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, R1, R0.w;\n"
+ "MUL R2.xyz, R0.w, R1;\n"
"MAD R3.xyz, R0, R1.w, R2;\n"
- "ADD R2.w, -R1, c[4].z;\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[4].w;\n"
+ "MAX R2.xyz, R0, c[6].w;\n"
"MUL R5.xyz, R0, R2.w;\n"
- "ADD R3.w, -R0, c[4].z;\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"
@@ -2038,50 +2008,49 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_HARDLIGHT_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\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"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\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 R2.w, -R1, c[4].z;\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[4].x;\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[4].z;\n"
- "MUL R0.xyz, R0, c[4].x;\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[4].x, R4;\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"
@@ -2093,10 +2062,9 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODES_SOFTLIGHT_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..3],\n"
- " { 2, 4, 1, 9.9999997e-06 },\n"
- " program.local[5..6],\n"
- " { 8, 3 } };\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"
@@ -2104,151 +2072,148 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\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"
- "MUL R0.x, R0, c[4];\n"
"MAD R0.y, R0.x, R0.x, -R0;\n"
- "MAX R0.z, R1.w, c[4].w;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "MUL R6.xyz, -R2, c[7].x;\n"
- "MAD R3.xyz, -R1, R2.w, c[4].z;\n"
"RSQ R0.y, R0.y;\n"
"RCP R0.y, R0.y;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "MOV R0.y, c[4].x;\n"
- "MUL R0.y, c[5].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.x, R0, 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 R4.xyz, R0, c[4].x, -R0.w;\n"
- "MUL R5.xyz, R3, R4;\n"
- "MAD R3.xyz, -R3, R4, R0.w;\n"
- "ADD R6.xyz, R6, c[7].y;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MAD R5.xyz, -R5, R6, R0.w;\n"
- "MUL R3.xyz, R1, R3;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R1.w, -R1;\n"
- "MUL R6.xyz, R2, R4;\n"
- "MUL R2.xyz, R1, R5;\n"
- "MUL R4.xyz, R0, c[4].x;\n"
- "MAD R6.xyz, R1, R0.w, R6;\n"
- "MUL R5.xyz, R1, c[7].x;\n"
- "ADD R6.xyz, R6, -R2;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R2.xyz, R2, R5;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\n"
- "ADD R2.w, -R1, c[4].z;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].z;\n"
- "MAD result.color.xyz, R1, R2.y, R0;\n"
- "MAD result.color.w, -R0, R1, R2.x;\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..3],\n"
- " { 2, 4 },\n"
- " program.local[5..6] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\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, R1, R0.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[4].x, R0;\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..3],\n"
- " { 2, 4, 1 },\n"
- " program.local[5..6] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "RCP R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "MUL R1.xy, fragment.position, c[6];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R0.x, -R0, R0.y;\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.x, R0, R0.z;\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, R1, R0.w;\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[4].x, R3;\n"
- "ADD R2.w, -R1, c[4].z;\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[4].z;\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"
@@ -2256,35 +2221,34 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODE_BLEND_MODE_MASK =
"!!ARBfp1.0\n"
- "PARAM c[9] = { program.local[0..3],\n"
- " { 2, 4 },\n"
- " program.local[5..8] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\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.z, c[4].x;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "RCP R1.y, R0.z;\n"
- "ADD R0.xy, fragment.position, c[6];\n"
- "MUL R0.xy, R0, c[7];\n"
- "TEX R0, R0, texture[0], 2D;\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[8];\n"
+ "DP4 R1.y, R0, c[7];\n"
"TEX R0, R1, texture[1], 1D;\n"
"MUL result.color, R0, R1.y;\n"
"END\n"
@@ -2292,28 +2256,27 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MODE_BLEND_MODE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[6] = { program.local[0..3],\n"
- " { 2, 4 },\n"
- " program.local[5] };\n"
+ "PARAM c[6] = { program.local[0..4],\n"
+ " { 2, 4 } };\n"
"TEMP R0;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "ADD R0.x, R0, R0.y;\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.z, R0, R0.w;\n"
- "MUL R0.z, c[5].x, -R0;\n"
- "MUL R0.y, R0.z, c[4];\n"
- "MUL R0.x, R0, c[4];\n"
- "MAD R0.y, R0.x, R0.x, -R0;\n"
- "MOV R0.z, c[4].x;\n"
- "RSQ R0.y, R0.y;\n"
- "MUL R0.z, c[5].x, R0;\n"
- "RCP R0.y, R0.y;\n"
- "RCP R0.z, R0.z;\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"
@@ -2322,450 +2285,450 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_RADIAL_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SIMPLE_PORTER_DUFF =
"!!ARBfp1.0\n"
- "PARAM c[13] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494 },\n"
- " program.local[10..12] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[10].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, c[12].y;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[12].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "ADD R2.w, -R1, c[7];\n"
- "MUL R0.xyz, R0, c[11].y;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "MUL R0.xyz, R1, c[11].z;\n"
- "ADD R3.z, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R0, R3.z, R2;\n"
- "MUL R0.y, R0.w, R2.w;\n"
- "MUL R0.x, R0.w, R1.w;\n"
- "MUL R0.z, R1.w, R3;\n"
- "DP3 R2.w, R0, c[11];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494 },\n"
- " program.local[10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[10].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2.x, -R1.w, c[7].w;\n"
- "MUL R2.xyz, R0, R2.x;\n"
- "MAD R0.xyz, R0, R1, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494 },\n"
- " program.local[10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[0];\n"
- "ABS R0.w, R0.x;\n"
- "ABS R0.z, R0.y;\n"
- "ADD R0.z, R0, -R0.w;\n"
- "ADD R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\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.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2, R0, R1;\n"
- "MAD R2, -R0, R1, R2;\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 2 },\n"
- " program.local[10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[7];\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\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[9].y;\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[7].w;\n"
- "MAD R3.xyz, R3, c[9].y, R4;\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[9].y;\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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\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..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494 },\n"
- " program.local[10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\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, -R1, c[7];\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494 },\n"
- " program.local[10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\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, -R1, c[7];\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 1e-06 },\n"
- " program.local[10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\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[9].y;\n"
+ "MAX R1.x, R0.w, c[10].w;\n"
"RCP R1.x, R1.x;\n"
- "MAD R1.xyz, -R0, R1.x, c[7].w;\n"
- "MAX R2.xyz, R1, c[9].y;\n"
- "MUL R1.xy, fragment.position, c[10];\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[7];\n"
+ "ADD R2.w, -R0, c[10].z;\n"
"MUL R3.xyz, R1, R2.w;\n"
- "ADD R2.w, -R1, c[7];\n"
+ "ADD R2.w, -R1, c[10].z;\n"
"MAD R4.xyz, R0, R2.w, R3;\n"
- "MUL R3.xyz, R1, R0.w;\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"
@@ -2778,70 +2741,70 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\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..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 9.9999997e-06 },\n"
- " program.local[10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
+ "ADD R1.x, R0.y, c[8];\n"
"ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
+ "CMP R0.y, -R0.z, R0, R1.x;\n"
"ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[7];\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\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, R1, R0.w;\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].y;\n"
- "ADD R3.w, -R0, c[7];\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"
@@ -2856,74 +2819,74 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\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..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 2 },\n"
- " program.local[10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[7];\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\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[9].y;\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[7];\n"
- "MAD R3.xyz, R3, c[9].y, R4;\n"
- "MUL R0.xyz, R0, c[9].y;\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"
@@ -2931,23 +2894,22 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\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[12] = { program.local[0..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 9.9999997e-06, 2, 8 },\n"
- " program.local[10],\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"
@@ -2956,326 +2918,327 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
+ "ADD R1.x, R0.y, c[8];\n"
"ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
+ "CMP R0.y, -R0.z, R0, R1.x;\n"
"ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MOV R1.x, c[7].y;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MUL R0.zw, fragment.position.xyxy, c[10].xyxy;\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.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\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"
- "MAX R0.z, R1.w, c[9].y;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "RSQ R3.w, R2.x;\n"
- "RSQ R4.y, R2.z;\n"
- "RCP R4.x, R3.w;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MAD R3.xyz, R0, c[9].z, -R0.w;\n"
- "RSQ R3.w, R2.y;\n"
- "RCP R4.z, R4.y;\n"
- "RCP R4.y, R3.w;\n"
- "MAD R4.xyz, R4, R1.w, -R1;\n"
- "MUL R6.xyz, R4, R3;\n"
- "MUL R4.xyz, -R2, c[9].w;\n"
- "MAD R2.xyz, -R1, R2.w, c[7].w;\n"
- "ADD R5.xyz, R4, c[11].x;\n"
- "MUL R4.xyz, R2, R3;\n"
- "MAD R4.xyz, -R4, R5, R0.w;\n"
- "MAD R2.xyz, -R2, R3, R0.w;\n"
- "MAD R5.xyz, R1, R0.w, R6;\n"
- "MUL R4.xyz, R1, R4;\n"
- "MUL R6.xyz, R1, c[9].w;\n"
- "ADD R5.xyz, R5, -R4;\n"
- "SGE R6.xyz, R6, R1.w;\n"
- "MUL R5.xyz, R6, R5;\n"
- "ADD R3.xyz, R4, R5;\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"
- "MUL R4.xyz, R0, c[9].z;\n"
- "ADD R3.xyz, R3, -R2;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R3.xyz, R4, R3;\n"
- "ADD R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[7];\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R1, R2.x, R0;\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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\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..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 2 },\n"
- " program.local[10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[10].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R3.xyz, R0, R1;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "MAD R2.xyz, -R0, c[9].y, R3;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..5],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[8],\n"
- " { 0.15915494, 2 },\n"
- " program.local[10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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 R0.w, R0.y, c[6].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[6].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[7].y;\n"
- "CMP R0.x, R0, c[7], R1;\n"
- "MAD R0.w, R0, c[6].z, -c[6];\n"
- "MUL R1.xy, fragment.position, c[10];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[7].z, c[7].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[8];\n"
- "MUL R0.x, R0, c[9];\n"
- "FLR R0.y, R0.x;\n"
- "ADD R0.x, R0, -R0.y;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MAD R3.xyz, R0, R1.w, R2;\n"
- "MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[9].y, R3;\n"
- "ADD R2.w, -R1, c[7];\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[7].w;\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7..9] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
- "FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\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[9].y;\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, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[9].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R2.w, -R1, c[4];\n"
- "MUL R0.xyz, R0, c[8].y;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[4].w;\n"
- "MUL R1.xyz, R1, c[8].z;\n"
- "MAD result.color.xyz, R1, R2.x, R0;\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[8];\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..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\n"
- "FLR R0.y, R0.x;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\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[4].w;\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[4].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"
@@ -3283,46 +3246,46 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SCREEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, 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[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"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
@@ -3333,64 +3296,64 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_OVERLAY_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 2 },\n"
- " program.local[7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[4];\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, 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[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"
- "MUL R2.xyz, R2, c[6].y;\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[4];\n"
- "MAD R0.xyz, R0, c[6].y, R3;\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[6].y;\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"
@@ -3401,57 +3364,57 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_DARKEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, 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[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, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MIN R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4];\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[4].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"
@@ -3459,57 +3422,57 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_LIGHTEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, 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[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, R1, R0.w;\n"
+ "MUL R3.xyz, R0.w, R1;\n"
"MAX R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4];\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[4].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"
@@ -3517,59 +3480,59 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORDODGE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 1e-06 },\n"
- " program.local[7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, 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[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[6].y;\n"
+ "MAX R1.x, R0.w, c[7].w;\n"
"RCP R1.x, R1.x;\n"
- "MAD R1.xyz, -R0, R1.x, c[4].w;\n"
- "MAX R2.xyz, R1, c[6].y;\n"
- "MUL R1.xy, fragment.position, c[7];\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[4];\n"
+ "ADD R2.w, -R0, c[7].z;\n"
"MUL R3.xyz, R1, R2.w;\n"
- "ADD R2.w, -R1, c[4];\n"
+ "ADD R2.w, -R1, c[7].z;\n"
"MAD R3.xyz, R0, R2.w, R3;\n"
- "MUL R1.xyz, R1, R0.w;\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"
@@ -3587,60 +3550,60 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_COLORBURN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 9.9999997e-06 },\n"
- " program.local[7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
+ "ADD R1.x, R0.y, c[5];\n"
"ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
+ "CMP R0.y, -R0.z, R0, R1.x;\n"
"ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[4];\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\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, R1, R0.w;\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[6].y;\n"
+ "MAX R2.xyz, R0, c[7].w;\n"
"MUL R5.xyz, R0, R2.w;\n"
- "ADD R3.w, -R0, c[4];\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"
@@ -3659,64 +3622,64 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_HARDLIGHT_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[8] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 2 },\n"
- " program.local[7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "ADD R2.w, -R1, c[4];\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, 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[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[6].y;\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[4];\n"
- "MUL R0.xyz, R0, c[6].y;\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[6].y, R4;\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"
@@ -3728,12 +3691,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODES_SOFTLIGHT_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[9] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 9.9999997e-06, 2, 8 },\n"
- " program.local[7],\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"
@@ -3742,190 +3704,191 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
+ "ADD R1.x, R0.y, c[5];\n"
"ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
+ "CMP R0.y, -R0.z, R0, R1.x;\n"
"ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MOV R1.x, c[4].y;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\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.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, c[6];\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"
- "MAX R0.z, R1.w, c[6].y;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "RSQ R3.w, R2.x;\n"
- "RSQ R4.y, R2.z;\n"
- "RCP R4.x, R3.w;\n"
"ADD R0.x, R0, -R0.y;\n"
"TEX R0, R0, texture[1], 1D;\n"
- "MAD R3.xyz, R0, c[6].z, -R0.w;\n"
- "RSQ R3.w, R2.y;\n"
- "RCP R4.z, R4.y;\n"
- "RCP R4.y, R3.w;\n"
- "MAD R4.xyz, R4, R1.w, -R1;\n"
- "MUL R6.xyz, R4, R3;\n"
- "MUL R4.xyz, -R2, c[6].w;\n"
- "MAD R2.xyz, -R1, R2.w, c[4].w;\n"
- "ADD R5.xyz, R4, c[8].x;\n"
- "MUL R4.xyz, R2, R3;\n"
- "MAD R4.xyz, -R4, R5, R0.w;\n"
- "MAD R2.xyz, -R2, R3, R0.w;\n"
- "MAD R5.xyz, R1, R0.w, R6;\n"
- "MUL R4.xyz, R1, R4;\n"
- "MUL R6.xyz, R1, c[6].w;\n"
- "ADD R5.xyz, R5, -R4;\n"
- "SGE R6.xyz, R6, R1.w;\n"
- "MUL R5.xyz, R6, R5;\n"
- "ADD R3.xyz, R4, R5;\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"
- "MUL R4.xyz, R0, c[6].z;\n"
- "ADD R3.xyz, R3, -R2;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R3.xyz, R4, R3;\n"
- "ADD R2.xyz, R2, R3;\n"
- "ADD R2.w, -R1, c[4];\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, R0.w, R1.w;\n"
- "ADD R2.y, -R0.w, c[4].w;\n"
- "MAD result.color.xyz, R1, R2.y, R0;\n"
- "MAD result.color.w, -R0, R1, R2.x;\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..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 2 },\n"
- " program.local[7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, 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[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, R1, R0.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].y, R0;\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..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494, 2 },\n"
- " program.local[7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, 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[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, R1, R0.w;\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].y, R3;\n"
- "ADD R2.w, -R1, c[4];\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[4].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"
@@ -3933,49 +3896,49 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODE_BLEND_MODE_MASK =
"!!ARBfp1.0\n"
- "PARAM c[10] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 },\n"
- " program.local[7..9] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.y, R0.w;\n"
- "RCP R1.x, R1.x;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.z, R0.x, R0.y, c[5].x;\n"
- "MUL R1.x, R0.z, 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[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.xy, fragment.position, c[7];\n"
- "MUL R0.xy, R0, c[8];\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[9];\n"
+ "DP4 R1.y, R0, c[6];\n"
"TEX R0, R1, texture[1], 1D;\n"
"MUL result.color, R0, R1.y;\n"
"END\n"
@@ -3983,42 +3946,43 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MODE_BLEND_MODE_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..2],\n"
- " { 0.0020000001, 9.9999997e-10, 0.1963, 0.9817 },\n"
- " { 2.3561945, 0.78539819, -1, 1 },\n"
- " program.local[5],\n"
- " { 0.15915494 } };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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 R0.w, R0.y, c[3].x;\n"
- "ABS R0.z, R0;\n"
- "CMP R0.y, -R0.z, R0, R0.w;\n"
- "ABS R0.z, -R0.y;\n"
- "ADD R0.z, R0, c[3].y;\n"
- "ADD R0.w, R0.x, R0.z;\n"
- "ADD R1.x, R0.z, -R0;\n"
- "RCP R1.x, R1.x;\n"
- "RCP R1.y, R0.w;\n"
- "MUL R0.w, R0, R1.x;\n"
- "ADD R0.z, R0.x, -R0;\n"
- "MUL R0.z, R0, R1.y;\n"
- "CMP R0.z, R0.x, R0.w, R0;\n"
- "MUL R0.w, R0.z, R0.z;\n"
- "MOV R1.x, c[4].y;\n"
- "CMP R0.y, -R0, c[4].z, c[4].w;\n"
- "MAD R0.w, R0, c[3].z, -c[3];\n"
- "CMP R0.x, R0, c[4], R1;\n"
- "MAD R0.x, R0.w, R0.z, R0;\n"
- "MAD R0.x, R0, R0.y, c[5];\n"
- "MUL R0.x, R0, 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[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"
@@ -4027,45 +3991,43 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_CONICAL_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SIMPLE_PORTER_DUFF =
"!!ARBfp1.0\n"
- "PARAM c[11] = { program.local[0..7],\n"
- " { 1 },\n"
- " program.local[9..10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, c[10].y;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[10].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "MUL R0.xyz, R0, c[9].y;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "MUL R0.xyz, R1, c[9].z;\n"
- "ADD R2.w, -R0, c[8].x;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R0.y, -R1.w, c[8].x;\n"
- "MUL R0.z, R1.w, R2.w;\n"
- "MUL R0.x, R0.w, R1.w;\n"
- "MUL R0.y, R0.w, R0;\n"
- "DP3 R2.w, R0, c[9];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -4076,30 +4038,30 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2.x, -R1.w, c[8];\n"
- "MUL R2.xyz, R0, R2.x;\n"
- "MAD R0.xyz, R0, R1, R2;\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"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -4110,25 +4072,25 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R2, R0, R1;\n"
- "MAD R2, -R0, R1, R2;\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -4141,16 +4103,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MUL R1.xy, fragment.position, c[7];\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"
@@ -4171,11 +4133,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -4188,32 +4150,32 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\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, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -4225,64 +4187,64 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\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, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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-06 } };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\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[7];\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, R1, R0.w;\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"
@@ -4295,11 +4257,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -4307,25 +4269,25 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
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-06 } };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\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 R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\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"
@@ -4340,18 +4302,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"MUL R4.xyz, R1, R3.w;\n"
"MAD R0.xyz, R0, R2.w, R4;\n"
"MUL R2.w, R0, R1;\n"
- "ADD R3.w, -R0, c[8].x;\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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -4365,16 +4326,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
+ "MUL R0.x, R0, c[0].z;\n"
"TEX R0, R0, texture[2], 1D;\n"
- "MUL R1.xy, fragment.position, c[7];\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"
@@ -4395,11 +4356,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -4407,8 +4368,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SOFTLIGHT =
"!!ARBfp1.0\n"
"PARAM c[10] = { program.local[0..7],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -4416,59 +4377,58 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R2.xyz, fragment.position.y, c[4];\n"
- "MAD R3.xyz, fragment.position.x, c[3], R2;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MAX R0.x, R1.w, c[8].y;\n"
- "RCP R2.w, R0.x;\n"
- "MUL R0.xyz, R1, R2.w;\n"
- "RSQ R0.w, R0.x;\n"
- "RSQ R2.y, R0.y;\n"
- "ADD R3.xyz, R3, c[5];\n"
- "RCP R2.x, R0.w;\n"
- "RCP R0.w, R3.z;\n"
- "MUL R3.xy, R3, R0.w;\n"
- "RSQ R0.w, R0.z;\n"
- "RCP R2.z, R0.w;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R6.xyz, R2, R1.w, -R1;\n"
- "MUL R2.xyz, -R0, c[8].w;\n"
- "ADD R5.xyz, R2, c[9].x;\n"
- "MAD R2.xyz, -R1, R2.w, c[8].x;\n"
- "MUL R3.xy, R3, c[6];\n"
- "ADD R0.w, R3.x, R3.y;\n"
- "MUL R0.w, R0, c[6].z;\n"
- "TEX R0, R0.w, texture[2], 1D;\n"
- "MAD R3.xyz, R0, c[8].z, -R0.w;\n"
- "MUL R4.xyz, R2, R3;\n"
- "MAD R4.xyz, -R4, R5, R0.w;\n"
- "MUL R5.xyz, R6, R3;\n"
- "MAD R2.xyz, -R2, R3, R0.w;\n"
- "MAD R6.xyz, R1, R0.w, R5;\n"
- "MUL R4.xyz, R1, R4;\n"
- "MUL R5.xyz, R1, c[8].w;\n"
- "ADD R6.xyz, R6, -R4;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R3.xyz, R4, 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 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"
- "MUL R4.xyz, R0, c[8].z;\n"
- "ADD R3.xyz, R3, -R2;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R3.xyz, R4, R3;\n"
- "ADD R2.xyz, R2, R3;\n"
"ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -4481,106 +4441,104 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "ADD R3.xyz, R0, R1;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "MAD R2.xyz, -R0, c[8].x, R3;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[6].z;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 1D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MAD R3.xyz, R0, R1.w, R2;\n"
- "MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[8].y, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..4],\n"
- " { 1 },\n"
- " program.local[6..7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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"
+ "MUL R0.zw, fragment.position.xyxy, c[6].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R2.xyz, R1, c[7].y;\n"
- "MUL R0.x, R0, c[3].z;\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, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[7].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "MUL R0.xyz, R0, c[6].y;\n"
- "ADD R2.w, -R1, c[5].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[5];\n"
- "MUL R1.xyz, R1, c[6].z;\n"
- "MAD result.color.xyz, R1, R2.x, R0;\n"
- "ADD R0.y, -R1.w, c[5].x;\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, R0;\n"
- "DP3 result.color.w, R0, c[6];\n"
+ "MUL R0.y, R0.w, R2.w;\n"
+ "DP3 result.color.w, R0, c[5];\n"
"END\n"
;
@@ -4591,16 +4549,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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[3].z;\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"
@@ -4618,16 +4576,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\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[3].z;\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"
@@ -4642,14 +4600,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\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"
@@ -4683,19 +4641,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\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, R1, R0.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"
@@ -4714,19 +4672,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\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, R1, R0.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"
@@ -4740,19 +4698,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
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-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\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"
@@ -4764,7 +4722,7 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"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, R1, R0.w;\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"
@@ -4783,25 +4741,25 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
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-06 } };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\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 R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\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"
@@ -4814,9 +4772,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"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"
- "ADD R3.w, -R0, c[5].x;\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"
@@ -4835,14 +4792,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\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"
@@ -4871,8 +4828,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_SOFTLIGHT_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[7] = { program.local[0..4],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -4880,54 +4837,53 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R2.xyz, fragment.position.y, c[1];\n"
- "MAD R3.xyz, fragment.position.x, c[0], R2;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R1, R0, texture[0], 2D;\n"
- "MAX R0.x, R1.w, c[5].y;\n"
- "RCP R2.w, R0.x;\n"
- "MUL R0.xyz, R1, R2.w;\n"
- "RSQ R0.w, R0.x;\n"
- "RSQ R2.y, R0.y;\n"
- "ADD R3.xyz, R3, c[2];\n"
- "RCP R2.x, R0.w;\n"
- "RCP R0.w, R3.z;\n"
- "MUL R3.xy, R3, R0.w;\n"
- "RSQ R0.w, R0.z;\n"
- "RCP R2.z, R0.w;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R6.xyz, R2, R1.w, -R1;\n"
- "MUL R2.xyz, -R0, c[5].w;\n"
- "ADD R5.xyz, R2, c[6].x;\n"
- "MAD R2.xyz, -R1, R2.w, c[5].x;\n"
- "MUL R3.xy, R3, c[3];\n"
- "ADD R0.w, R3.x, R3.y;\n"
- "MUL R0.w, R0, c[3].z;\n"
- "TEX R0, R0.w, texture[1], 1D;\n"
- "MAD R3.xyz, R0, c[5].z, -R0.w;\n"
- "MUL R4.xyz, R2, R3;\n"
- "MAD R4.xyz, -R4, R5, R0.w;\n"
- "MUL R5.xyz, R6, R3;\n"
- "MAD R2.xyz, -R2, R3, R0.w;\n"
- "MAD R6.xyz, R1, R0.w, R5;\n"
- "MUL R4.xyz, R1, R4;\n"
- "MUL R5.xyz, R1, c[5].w;\n"
- "ADD R6.xyz, R6, -R4;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R3.xyz, R4, 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 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"
- "MUL R4.xyz, R0, c[5].z;\n"
- "ADD R3.xyz, R3, -R2;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R3.xyz, R4, R3;\n"
- "ADD R2.xyz, R2, R3;\n"
+ "SGE R3.xyz, R3, R0.w;\n"
+ "MAD R2.xyz, R3, R4, R2;\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"
+ "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"
;
@@ -4939,19 +4895,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
- "MUL R1.xy, fragment.position, c[4];\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"
- "TEX R1, R1, texture[0], 2D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.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"
@@ -4963,30 +4919,30 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MODES_EXCLUSION_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\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, R1, R0.w;\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].y, R3;\n"
- "ADD R2.w, -R1, c[5].x;\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].x;\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"
@@ -4997,18 +4953,18 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"PARAM c[7] = { program.local[0..6] };\n"
"TEMP R0;\n"
"TEMP R1;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3].xyxy;\n"
+ "MUL R0.zw, R0, c[0].xyxy;\n"
"ADD R1.x, R0.z, R0.w;\n"
- "ADD R0.xy, fragment.position, c[4];\n"
- "MUL R0.xy, R0, c[5];\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[3].z;\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"
@@ -5018,58 +4974,55 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_LINEAR_COMPOSITION_MOD
"!!ARBfp1.0\n"
"PARAM c[4] = { program.local[0..3] };\n"
"TEMP R0;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
+ "MUL R0.xy, R0, c[0];\n"
"ADD R0.x, R0, R0.y;\n"
- "MUL R0.x, R0, c[3].z;\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..7],\n"
- " { 1 },\n"
- " program.local[9..10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "MUL R2.xyz, R1, c[10].y;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[10].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "MUL R0.xyz, R0, c[9].y;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R2.w, -R0, c[8].x;\n"
- "MUL R0.xyz, R1, c[9].z;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R0.y, -R1.w, c[8].x;\n"
- "MUL R0.z, R1.w, R2.w;\n"
- "MUL R0.x, R0.w, R1.w;\n"
- "MUL R0.y, R0.w, R0;\n"
- "DP3 R2.w, R0, c[9];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, 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"
+ "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"
;
@@ -5080,29 +5033,28 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\n"
- "RCP R1.x, R0.z;\n"
- "MUL R0.xy, R0, R1.x;\n"
- "MUL R0.xy, R0, c[6];\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "ADD R2.x, -R1.w, c[8];\n"
- "MUL R2.xyz, R0, R2.x;\n"
- "MAD R0.xyz, R0, R1, 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"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -5113,24 +5065,23 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "ADD R2, R0, R1;\n"
- "MAD R2, -R0, R1, R2;\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -5143,15 +5094,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\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"
@@ -5172,11 +5122,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -5189,31 +5139,30 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\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, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -5225,62 +5174,60 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\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, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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-06 } };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\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 R1.xyz, -R0, R1.x, c[8].x;\n"
- "MAX R2.xyz, R1, c[8].y;\n"
- "MUL R1.xy, fragment.position, c[7];\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, R1, R0.w;\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"
@@ -5293,11 +5240,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -5305,24 +5252,23 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
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-06 } };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\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 R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\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"
@@ -5337,18 +5283,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"MUL R4.xyz, R1, R3.w;\n"
"MAD R0.xyz, R0, R2.w, R4;\n"
"MUL R2.w, R0, R1;\n"
- "ADD R3.w, -R0, c[8].x;\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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -5362,15 +5307,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
+ "MUL R0.xy, R0, c[0];\n"
"TEX R0, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\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"
@@ -5391,11 +5335,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -5403,8 +5347,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_SOFTLIGHT =
"!!ARBfp1.0\n"
"PARAM c[10] = { program.local[0..7],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -5412,58 +5356,56 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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"
- "MUL R0.xy, R0, c[6];\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MAX R0.z, R1.w, c[8].y;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "MUL R6.xyz, -R2, c[8].w;\n"
- "MAD R3.xyz, -R1, R2.w, c[8].x;\n"
- "MOV R0.y, -R0;\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, R0, c[8].z, -R0.w;\n"
- "MUL R5.xyz, R3, R4;\n"
- "MAD R3.xyz, -R3, R4, R0.w;\n"
- "ADD R6.xyz, R6, c[9].x;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MAD R5.xyz, -R5, R6, R0.w;\n"
- "MUL R3.xyz, R1, R3;\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"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R1.w, -R1;\n"
- "MUL R6.xyz, R2, R4;\n"
- "MUL R2.xyz, R1, R5;\n"
- "MAD R6.xyz, R1, R0.w, R6;\n"
- "MUL R4.xyz, R0, c[8].z;\n"
- "MUL R5.xyz, R1, c[8].w;\n"
- "ADD R6.xyz, R6, -R2;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R2.xyz, R2, R5;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\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[0];\n"
- "MUL R0.xy, R0, c[1];\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[2];\n"
+ "DP4 R0.x, R0, c[7];\n"
"MAD result.color, R0.x, R2, R1;\n"
"END\n"
;
@@ -5476,103 +5418,98 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "ADD R3.xyz, R0, R1;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "MAD R2.xyz, -R0, c[8].x, R3;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "TEX R0, R0, texture[2], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MAD R3.xyz, R0, R1.w, R2;\n"
- "MUL R2.xyz, R0, R1;\n"
- "MAD R2.xyz, -R2, c[8].y, R3;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..4],\n"
- " { 1 },\n"
- " program.local[6..7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MUL R2.xyz, R1, c[7].y;\n"
- "MOV R0.y, -R0;\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, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[7].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "MUL R0.xyz, R0, c[6].y;\n"
- "ADD R2.w, -R1, c[5].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[5];\n"
- "MUL R1.xyz, R1, c[6].z;\n"
- "MAD result.color.xyz, R1, R2.x, R0;\n"
- "ADD R0.y, -R1.w, c[5].x;\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, R0;\n"
- "DP3 result.color.w, R0, c[6];\n"
+ "MUL R0.y, R0.w, R2.w;\n"
+ "DP3 result.color.w, R0, c[5];\n"
"END\n"
;
@@ -5583,15 +5520,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
- "RCP R1.x, R0.z;\n"
- "MUL R0.xy, R0, R1.x;\n"
- "MUL R0.xy, R0, c[3];\n"
- "MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -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 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"
@@ -5609,15 +5545,14 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
"MUL R0.zw, fragment.position.xyxy, c[4].xyxy;\n"
"TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\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"
@@ -5632,13 +5567,12 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\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"
@@ -5672,18 +5606,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\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, R1, R0.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"
@@ -5702,18 +5635,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\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, R1, R0.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"
@@ -5727,41 +5659,40 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
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-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\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 R1.xyz, -R0, R1.x, c[5].x;\n"
- "MAX R2.xyz, R1, c[5].y;\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.w, -R0, c[5].x;\n"
- "MUL R3.xyz, R1, R2.w;\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 R3.xyz, R0, R2.w, R3;\n"
- "MUL R1.xyz, R1, R0.w;\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 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"
+ "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 R3.xyz, R3, -R2;\n"
+ "ADD R2.xyz, R2, -R3;\n"
"SGE R0.xyz, R0, R2.w;\n"
- "MAD result.color.xyz, R0, R3, R2;\n"
+ "MAD result.color.xyz, R0, R2, R3;\n"
"MAD result.color.w, -R0, R1, R1.x;\n"
"END\n"
;
@@ -5769,24 +5700,23 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
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-06 } };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\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 R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R2.xyz, R1, R0.w;\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"
@@ -5799,9 +5729,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"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"
- "ADD R3.w, -R0, c[5].x;\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"
@@ -5820,13 +5749,12 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R2;\n"
"TEMP R3;\n"
"TEMP R4;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\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"
@@ -5836,27 +5764,27 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"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"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R2.w, -R0, c[5].y;\n"
"MUL R0.xyz, R0, c[5].x;\n"
- "MAD R2.xyz, R1, R2.w, R2;\n"
+ "ADD R2.w, -R0, c[5].y;\n"
"MAD R3.xyz, R3, c[5].x, R4;\n"
- "MAD R1.xyz, R1, R2.w, R3;\n"
- "ADD R2.w, R0, R1;\n"
- "ADD R2.xyz, R2, -R1;\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, R2, R1;\n"
- "MAD result.color.w, -R0, R1, R2;\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, 9.9999997e-06, 2, 8 },\n"
- " { 3 } };\n"
+ " { 1, 2, 9.9999997e-006, 4 },\n"
+ " { 16, 12, 3 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
@@ -5864,53 +5792,51 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R4;\n"
"TEMP R5;\n"
"TEMP R6;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\n"
- "RCP R0.z, R0.z;\n"
- "MUL R0.xy, R0, R0.z;\n"
- "MUL R0.xy, R0, c[3];\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"
- "MAX R0.z, R1.w, c[5].y;\n"
- "RCP R2.w, R0.z;\n"
- "MUL R2.xyz, R1, R2.w;\n"
- "MUL R6.xyz, -R2, c[5].w;\n"
- "MAD R3.xyz, -R1, R2.w, c[5].x;\n"
- "MOV R0.y, -R0;\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, R0, c[5].z, -R0.w;\n"
- "MUL R5.xyz, R3, R4;\n"
- "MAD R3.xyz, -R3, R4, R0.w;\n"
- "ADD R6.xyz, R6, c[6].x;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MAD R5.xyz, -R5, R6, R0.w;\n"
- "MUL R3.xyz, R1, R3;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R1.w, -R1;\n"
- "MUL R6.xyz, R2, R4;\n"
- "MUL R2.xyz, R1, R5;\n"
- "MUL R4.xyz, R0, c[5].z;\n"
- "MAD R6.xyz, R1, R0.w, R6;\n"
- "MUL R5.xyz, R1, c[5].w;\n"
- "ADD R6.xyz, R6, -R2;\n"
- "SGE R5.xyz, R5, R1.w;\n"
- "MUL R5.xyz, R5, R6;\n"
- "ADD R2.xyz, R2, R5;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "SGE R4.xyz, R4, R0.w;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\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 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"
+ "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"
;
@@ -5922,18 +5848,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[4];\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"
- "TEX R1, R1, texture[0], 2D;\n"
"MUL R2.xyz, R0, R1.w;\n"
- "MUL R3.xyz, R1, R0.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"
@@ -5945,29 +5870,28 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MODES_EXCLUSION_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 1, 2 } };\n"
+ " { 2, 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "MUL R1.xy, fragment.position, c[4];\n"
- "TEX R1, R1, texture[0], 2D;\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, R1, R0.w;\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].y, R3;\n"
- "ADD R2.w, -R1, c[5].x;\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].x;\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"
@@ -5978,19 +5902,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"PARAM c[7] = { program.local[0..6] };\n"
"TEMP R0;\n"
"TEMP R1;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R1.xyz, R0, c[2];\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[4];\n"
- "MUL R0.xy, R0, c[5];\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[3];\n"
- "MOV R0.x, R1;\n"
- "MOV R0.y, -R1;\n"
- "TEX R0, R0, texture[1], 2D;\n"
+ "MUL R1.xy, R1, c[0];\n"
+ "TEX R0, R1, texture[1], 2D;\n"
"MUL result.color, R0, R1.z;\n"
"END\n"
;
@@ -5999,58 +5921,55 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_TEXTURE_COMPOSITION_MO
"!!ARBfp1.0\n"
"PARAM c[4] = { program.local[0..3] };\n"
"TEMP R0;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\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..7],\n"
- " { 1 },\n"
- " program.local[9..10] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "MUL R2.xyz, R1, c[10].y;\n"
- "MUL R3.xyz, R2, R0.w;\n"
- "MUL R2.xyz, R0, c[10].x;\n"
- "MAD R2.xyz, R2, R1.w, R3;\n"
- "ADD R3.xy, fragment.position, c[0];\n"
- "MUL R0.xyz, R0, c[9].y;\n"
- "ADD R2.w, -R1, c[8].x;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R2.w, -R0, c[8].x;\n"
- "MUL R0.xyz, R1, c[9].z;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "ADD R0.y, -R1.w, c[8].x;\n"
- "MUL R0.z, R1.w, R2.w;\n"
- "MUL R0.x, R0.w, R1.w;\n"
- "MUL R0.y, R0.w, R0;\n"
- "DP3 R2.w, R0, c[9];\n"
- "MUL R3.xy, R3, c[1];\n"
- "TEX R0, R3, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -6061,58 +5980,59 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "MOV R0.y, -R0;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "ADD R2.x, -R1.w, c[8];\n"
- "MUL R2.xyz, R0, R2.x;\n"
- "MAD R0.xyz, R0, R1, R2;\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"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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[8] = { program.local[0..7] };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[2], 2D;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "ADD R3.xy, fragment.position, c[0];\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"
- "MUL R1, fragment.color.primary, R1.x;\n"
"ADD R2, R1, R0;\n"
"MAD R2, -R1, R0, R2;\n"
- "MUL R3.xy, R3, c[1];\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[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6120,47 +6040,47 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_OVERLAY =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 2, 1 } };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[2], 2D;\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[8].y;\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].x;\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].y;\n"
- "MAD R3.xyz, R3, c[8].x, R4;\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].x;\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[0];\n"
- "MUL R1.xy, R1, c[1];\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[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6173,32 +6093,32 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\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, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -6210,64 +6130,64 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "MUL R3.xyz, R1, R0.w;\n"
- "MUL R2.xyz, R0, R1.w;\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, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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-06 } };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\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 R0.xyz, -R1, R0.x, c[8].x;\n"
- "MAX R2.xyz, R0, c[8].y;\n"
- "MUL R0.xy, fragment.position, c[7];\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, R0, R1.w;\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"
@@ -6280,11 +6200,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"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[0];\n"
- "MUL R1.xy, R1, c[1];\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[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6292,25 +6212,25 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
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-06 } };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[2], 2D;\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.xy, fragment.position, c[7];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, R1.w;\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"
@@ -6325,18 +6245,17 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"MUL R4.xyz, R0, R3.w;\n"
"MAD R1.xyz, R1, R2.w, R4;\n"
"MUL R2.w, R1, R0;\n"
- "ADD R3.w, -R1, c[8].x;\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[0];\n"
- "MUL R1.xy, R1, c[1];\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[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6344,35 +6263,35 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_HARDLIGHT =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 2, 1 } };\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[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[2], 2D;\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[8].y;\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].x;\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].y;\n"
- "MAD R3.xyz, R3, c[8].x, R4;\n"
- "MUL R1.xyz, R1, c[8].x;\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"
@@ -6380,11 +6299,11 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"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[0];\n"
- "MUL R1.xy, R1, c[1];\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[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6392,68 +6311,67 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SOFTLIGHT =
"!!ARBfp1.0\n"
"PARAM c[10] = { program.local[0..7],\n"
- " { 1, 9.9999997e-06, 2, 8 },\n"
- " { 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.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R1.xyz, R0, c[5];\n"
- "RCP R0.z, R1.z;\n"
- "MUL R1.xy, R1, R0.z;\n"
- "MUL R1.xy, R1, c[6];\n"
- "MOV R1.y, -R1;\n"
- "MUL R0.xy, fragment.position, c[7];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "MAX R1.z, R0.w, c[8].y;\n"
- "RCP R2.w, R1.z;\n"
- "MUL R2.xyz, R0, R2.w;\n"
- "MUL R5.xyz, -R2, c[8].w;\n"
- "MAD R4.xyz, -R0, R2.w, c[8].x;\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 R3.xyz, R1, c[8].z, -R1.w;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MUL R4.xyz, R4, R3;\n"
- "ADD R5.xyz, R5, c[9].x;\n"
- "MUL R5.xyz, R4, R5;\n"
- "ADD R4.xyz, R1.w, -R4;\n"
- "ADD R2.w, -R0, c[8].x;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R0.w, -R0;\n"
- "MUL R3.xyz, R2, R3;\n"
- "ADD R2.xyz, R1.w, -R5;\n"
- "MAD R5.xyz, R0, R1.w, R3;\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"
- "MUL R3.xyz, R0, c[8].w;\n"
- "ADD R5.xyz, R5, -R2;\n"
- "SGE R3.xyz, R3, R0.w;\n"
- "MUL R3.xyz, R3, R5;\n"
- "ADD R2.xyz, R2, R3;\n"
- "MUL R3.xyz, R0, R4;\n"
- "MUL R4.xyz, R1, c[8].z;\n"
- "SGE R4.xyz, R4, R1.w;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, R2;\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 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[0];\n"
- "MUL R1.xy, R1, c[1];\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[2];\n"
+ "DP4 R1.x, R1, c[7];\n"
"MAD result.color, R1.x, R2, R0;\n"
"END\n"
;
@@ -6461,35 +6379,35 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_DIFFERENCE =
"!!ARBfp1.0\n"
"PARAM c[9] = { program.local[0..7],\n"
- " { 2 } };\n"
+ " { 1, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "MUL R0.zw, fragment.position.xyxy, c[7].xyxy;\n"
- "TEX R1, R0.zwzw, texture[0], 2D;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "ADD R3.xyz, R0, R1;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "MIN R0.xyz, R0, R2;\n"
- "MAD R2.xyz, -R0, c[8].x, R3;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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"
;
@@ -6501,72 +6419,69 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[4];\n"
- "MAD R0.xyz, fragment.position.x, c[3], R0;\n"
- "ADD R0.xyz, R0, c[5];\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[6];\n"
- "MOV R0.y, -R0;\n"
- "TEX R0.x, R0, texture[2], 2D;\n"
- "MUL R1.xy, fragment.position, c[7];\n"
- "TEX R1, R1, texture[0], 2D;\n"
- "MUL R0, fragment.color.primary, R0.x;\n"
- "MUL R2.xyz, R1, R0.w;\n"
- "MAD R3.xyz, R0, R1.w, R2;\n"
- "MUL R2.xyz, R0, R1;\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, -R1, c[8].x;\n"
- "MAD R0.xyz, R0, R2.w, R2;\n"
- "ADD R2.x, -R0.w, c[8];\n"
- "MAD R2.xyz, R1, R2.x, R0;\n"
- "ADD R0.z, R0.w, R1.w;\n"
- "MAD R2.w, -R0, R1, R0.z;\n"
- "ADD R0.xy, fragment.position, c[0];\n"
- "MUL R0.xy, R0, c[1];\n"
- "TEX R0, R0, texture[1], 2D;\n"
- "ADD R2, R2, -R1;\n"
- "DP4 R0.x, R0, c[2];\n"
- "MAD result.color, R0.x, R2, R1;\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..4],\n"
- " { 1 },\n"
- " program.local[6..7] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.w, -R0.y;\n"
- "MOV R0.z, R0.x;\n"
- "TEX R1.x, R0.zwzw, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, c[7].y;\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, R2, R1.w;\n"
- "MUL R2.xyz, R1, c[7].x;\n"
- "MUL R0.xyz, R0, c[6].z;\n"
- "MAD R2.xyz, R2, R0.w, R3;\n"
- "MUL R1.xyz, R1, c[6].y;\n"
- "ADD R2.w, -R0, c[5].x;\n"
- "MAD R1.xyz, R1, R2.w, R2;\n"
- "ADD R2.x, -R1.w, c[5];\n"
- "MAD result.color.xyz, R0, R2.x, R1;\n"
- "ADD R0.y, -R0.w, c[5].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, R0;\n"
- "DP3 result.color.w, R0, c[6];\n"
+ "MUL R0.y, R1.w, R2.w;\n"
+ "DP3 result.color.w, R0, c[5];\n"
"END\n"
;
@@ -6577,16 +6492,16 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R1.y, -R1;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "TEX R1.x, R1, texture[1], 2D;\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"
@@ -6600,21 +6515,21 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_SCREEN_NOMASK =
"!!ARBfp1.0\n"
- "PARAM c[5] = { program.local[0..4] };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.w, -R0.y;\n"
- "MOV R0.z, R0.x;\n"
- "TEX R1.x, R0.zwzw, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\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"
@@ -6624,36 +6539,36 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_OVERLAY_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 2, 1 } };\n"
+ " { 1, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\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].y;\n"
- "MUL R2.xyz, R2, c[5].x;\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].y;\n"
- "MAD R1.xyz, R1, c[5].x, R3;\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].x;\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"
@@ -6670,19 +6585,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\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, R0, R1.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"
@@ -6701,19 +6616,19 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\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, R0, R1.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"
@@ -6727,42 +6642,42 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
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-06 } };\n"
+ " { 1, 1e-006 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\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 R0.xyz, -R1, R0.x, c[5].x;\n"
- "MAX R2.xyz, R0, c[5].y;\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.w, -R1, c[5].x;\n"
- "MUL R3.xyz, R0, R2.w;\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 R3.xyz, R1, R2.w, R3;\n"
- "MUL R0.xyz, R0, R1.w;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.y, R2.y;\n"
- "RCP R2.z, R2.z;\n"
- "MAD R2.xyz, R0, R2, R3;\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 R3.xyz, R1.w, R0.w, R3;\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 R3.xyz, R3, -R2;\n"
+ "ADD R2.xyz, R2, -R3;\n"
"SGE R0.xyz, R0, R2.w;\n"
- "MAD result.color.xyz, R0, R3, R2;\n"
+ "MAD result.color.xyz, R0, R2, R3;\n"
"MAD result.color.w, -R1, R0, R1.x;\n"
"END\n"
;
@@ -6770,25 +6685,25 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
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-06 } };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\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.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "MUL R2.xyz, R0, R1.w;\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"
@@ -6801,9 +6716,8 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"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"
- "ADD R3.w, -R1, c[5].x;\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"
@@ -6816,133 +6730,132 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODES_HARDLIGHT_NOMASK =
"!!ARBfp1.0\n"
"PARAM c[6] = { program.local[0..4],\n"
- " { 2, 1 } };\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[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\n"
- "ADD R2.w, -R0, c[5].y;\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].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 R4.xyz, R1, R2.w;\n"
"MUL R3.xyz, R1, R0;\n"
- "MAD R2.xyz, R1, R2.w, R2;\n"
- "ADD R2.w, -R1, c[5].y;\n"
- "MUL R1.xyz, R1, c[5].x;\n"
- "MAD R2.xyz, R0, R2.w, R2;\n"
- "MAD R3.xyz, R3, c[5].x, R4;\n"
- "MAD R0.xyz, R0, R2.w, R3;\n"
- "ADD R2.w, R1, R0;\n"
- "ADD R2.xyz, R2, -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, R2, R0;\n"
- "MAD result.color.w, -R1, R0, R2;\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, 9.9999997e-06, 2, 8 },\n"
- " { 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.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R1.xyz, R0, c[2];\n"
- "RCP R0.z, R1.z;\n"
- "MUL R1.xy, R1, R0.z;\n"
- "MUL R1.xy, R1, c[3];\n"
- "MOV R1.y, -R1;\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].y;\n"
- "RCP R2.w, R1.z;\n"
- "MUL R2.xyz, R0, R2.w;\n"
- "MUL R5.xyz, -R2, c[5].w;\n"
- "MAD R4.xyz, -R0, R2.w, c[5].x;\n"
- "TEX R1.x, R1, texture[1], 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 R3.xyz, R1, c[5].z, -R1.w;\n"
- "RSQ R2.x, R2.x;\n"
- "RSQ R2.z, R2.z;\n"
- "RSQ R2.y, R2.y;\n"
- "MUL R4.xyz, R4, R3;\n"
- "ADD R5.xyz, R5, c[6].x;\n"
- "MUL R5.xyz, R4, R5;\n"
- "ADD R4.xyz, R1.w, -R4;\n"
- "RCP R2.x, R2.x;\n"
- "RCP R2.z, R2.z;\n"
- "RCP R2.y, R2.y;\n"
- "MAD R2.xyz, R2, R0.w, -R0;\n"
- "MUL R3.xyz, R2, R3;\n"
- "ADD R2.xyz, R1.w, -R5;\n"
- "MAD R5.xyz, R0, R1.w, R3;\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"
- "MUL R3.xyz, R0, c[5].w;\n"
- "ADD R5.xyz, R5, -R2;\n"
- "SGE R3.xyz, R3, R0.w;\n"
- "MUL R3.xyz, R3, R5;\n"
- "ADD R2.xyz, R2, R3;\n"
- "MUL R3.xyz, R0, R4;\n"
- "MUL R4.xyz, R1, c[5].z;\n"
- "ADD R2.xyz, R2, -R3;\n"
- "SGE R4.xyz, R4, R1.w;\n"
- "MUL R2.xyz, R4, R2;\n"
- "ADD R2.xyz, R3, 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 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"
+ "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"
- " { 2 } };\n"
+ " { 1, 2 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\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"
- "TEX R0, R0, texture[0], 2D;\n"
- "MUL R3.xyz, R0, R1.w;\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].x, R0;\n"
+ "MAD result.color.xyz, -R2, c[5].y, R0;\n"
"MAD result.color.w, -R1, R0, R1.x;\n"
"END\n"
;
@@ -6955,18 +6868,18 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
"TEMP R1;\n"
"TEMP R2;\n"
"TEMP R3;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\n"
- "TEX R1.x, R0, texture[1], 2D;\n"
- "MUL R0.xy, fragment.position, c[4];\n"
- "TEX R0, R0, texture[0], 2D;\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, R0, R1.w;\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"
@@ -6981,38 +6894,40 @@ static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MO
static const char *FragmentProgram_FRAGMENT_PROGRAM_BRUSH_PATTERN_COMPOSITION_MODE_BLEND_MODE_MASK =
"!!ARBfp1.0\n"
- "PARAM c[7] = { program.local[0..6] };\n"
+ "PARAM c[8] = { program.local[0..6],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
"TEMP R1;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R1.xyz, R0, c[2];\n"
- "RCP R0.z, R1.z;\n"
- "MUL R0.zw, R1.xyxy, R0.z;\n"
- "MUL R1.xy, R0.zwzw, c[3];\n"
- "MOV R1.y, -R1;\n"
- "ADD R0.xy, fragment.position, c[4];\n"
- "MUL R0.xy, R0, c[5];\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"
- "TEX R1.x, R1, texture[1], 2D;\n"
- "DP4 R0.x, R0, c[6];\n"
- "MUL R1, fragment.color.primary, R1.x;\n"
- "MUL result.color, R1, R0.x;\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[4] = { program.local[0..3] };\n"
+ "PARAM c[5] = { program.local[0..3],\n"
+ " { 1 } };\n"
"TEMP R0;\n"
- "MUL R0.xyz, fragment.position.y, c[1];\n"
- "MAD R0.xyz, fragment.position.x, c[0], R0;\n"
- "ADD R0.xyz, R0, c[2];\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[3];\n"
- "MOV R0.y, -R0;\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"
;
@@ -7195,19 +7110,19 @@ static const char *painter_fragment_program_sources[num_fragment_brushes][num_fr
static int painter_variable_locations[num_fragment_brushes][num_fragment_composition_modes][num_fragment_variables] = {
{
- { -1, -1, -1, 1, -1, 6, 2, -1, 5, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, 1, -1, -1, 2, -1, -1, 3, 1, 0, -1, 0, -1, -1, -1, -1, -1, },
- { -1, -1, -1, -1, -1, 3, -1, -1, 2, 0, -1, 0, -1, -1, -1, -1, -1, -1, -1, },
+ { -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, },
@@ -7219,154 +7134,154 @@ static int painter_variable_locations[num_fragment_brushes][num_fragment_composi
{ -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, 2, -1, -1, -1, 0, -1, -1, 0, -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, 4, 1, 5, 11, 2, -1, 10, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 9, 1, 0, 2, 0, -1, 8, 6, 3, -1, },
- { -1, -1, 1, -1, 2, 8, -1, -1, 7, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 6, -1, 0, 1, -1, -1, 5, 3, 0, -1, },
- { -1, -1, 1, 7, 2, -1, 8, -1, -1, -1, 0, -1, 1, 6, -1, 5, 3, 0, -1, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, 5, 3, 0, -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, 4, 1, 5, 12, 2, -1, 11, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 4, 1, 5, -1, 2, -1, -1, 10, 1, 0, 2, 0, -1, -1, -1, 3, 8, },
- { -1, -1, 1, -1, 2, 9, -1, -1, 8, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, 7, -1, 0, 1, -1, -1, -1, -1, 0, 5, },
- { -1, -1, 1, 8, 2, -1, 9, -1, -1, -1, 0, -1, 1, 7, -1, -1, -1, 0, 5, },
- { -1, -1, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, 0, 5, },
+ { -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, 6, 4, 1, 5, 10, 2, -1, 9, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 6, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, 2, 0, -1, -1, -1, 3, -1, },
- { -1, 3, 1, -1, 2, 7, -1, -1, 6, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, 1, -1, -1, -1, -1, 0, -1, },
- { -1, 3, 1, 5, 2, -1, 6, -1, -1, -1, 0, -1, 1, 4, -1, -1, -1, 0, -1, },
- { -1, 3, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, 0, -1, },
+ { -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, 4, 1, 5, 10, 2, -1, 9, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 1, -1, 1, -1, 2, 7, -1, -1, 6, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, 5, 2, -1, 6, -1, -1, -1, 0, -1, -1, 4, 3, -1, -1, 0, -1, },
- { 0, -1, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, 0, -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, 4, 1, 5, 10, 2, -1, 9, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 2, -1, 4, 1, 5, -1, 2, -1, -1, 7, 1, 0, -1, 0, 6, -1, -1, 3, -1, },
- { 1, -1, 1, -1, 2, 7, -1, -1, 6, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, -1, 2, -1, -1, -1, -1, 4, -1, 0, -1, -1, 3, -1, -1, 0, -1, },
- { 1, -1, 1, 5, 2, -1, 6, -1, -1, -1, 0, -1, -1, 4, 3, -1, -1, 0, -1, },
- { 0, -1, 1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, 0, -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, 2, -1, 3, -1, -1, 0, -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
index a56141c6d..0202fe171 100644
--- a/src/opengl/util/generator.cpp
+++ b/src/opengl/util/generator.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 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.
@@ -9,8 +10,8 @@
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
-** contained in the either Technology Preview License Agreement or the
-** Beta Release License Agreement.
+** contained in the Technology Preview License Agreement accompanying
+** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -20,21 +21,20 @@
** 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.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
**
-** 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.
**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
@@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE
QT_USE_NAMESPACE
+#define TAB " "
+
typedef QPair<QString, QString> QStringPair;
QString readSourceFile(const QString &sourceFile, bool fragmentProgram = false)
@@ -243,6 +245,30 @@ QString trimmed(QString source)
return result;
}
+void writeVariablesEnum(QTextStream &out, const char *name, const QSet<QString> &s)
+{
+ out << "enum " << name << " {";
+ QSet<QString>::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<QStringPair> &s)
+{
+ out << "enum " << name << " {";
+ QList<QStringPair>::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<QString> &variables,
const QList<QStringPair> &brushes,
const QList<QStringPair> &compositionModes,
@@ -257,30 +283,68 @@ void writeIncludeFile(const QSet<QString> &variables,
QTextStream out(&includeFile);
- QLatin1String tab(" ");
-
- out << "#ifndef FRAGMENTPROGRAMS_H\n"
- << "#define FRAGMENTPROGRAMS_H\n\n";
-
- out << "enum FragmentVariable {\n";
- foreach (QString str, variables)
- out << tab << "VAR_" << str.toUpper() << ",\n";
- out << "};\n\n";
-
- out << "enum FragmentBrushType {\n";
- foreach (QStringPair brush, brushes)
- out << tab << brush.first << ",\n";
- out << "};\n\n";
-
- out << "enum FragmentCompositionModeType {\n";
- foreach (QStringPair mode, compositionModes)
- out << tab << mode.first << ",\n";
- out << "};\n\n";
-
- out << "enum FragmentMaskType {\n";
- foreach (QStringPair mask, masks)
- out << tab << mask.first << ",\n";
- out << "};\n\n";
+ QLatin1String tab(TAB);
+
+ out << "/****************************************************************************\n"
+ "**\n"
+ "** Copyright (C) 2009 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"
+ "** No Commercial Usage\n"
+ "** This file contains pre-release code and may not be distributed.\n"
+ "** You may use this file in accordance with the terms and conditions\n"
+ "** contained in the Technology Preview License Agreement accompanying\n"
+ "** this package.\n"
+ "**\n"
+ "** GNU Lesser General Public License Usage\n"
+ "** Alternatively, this file may be used under the terms of the GNU Lesser\n"
+ "** General Public License version 2.1 as published by the Free Software\n"
+ "** Foundation and appearing in the file LICENSE.LGPL included in the\n"
+ "** packaging of this file. Please review the following information to\n"
+ "** ensure the GNU Lesser General Public License version 2.1 requirements\n"
+ "** will be met: 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"
+ "** If you have questions regarding the use of this file, please contact\n"
+ "** Nokia at qt-info@nokia.com.\n"
+ "**\n"
+ "**\n"
+ "**\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";
diff --git a/src/opengl/util/generator.pro b/src/opengl/util/generator.pro
index 9425dbea0..ac71934ec 100644
--- a/src/opengl/util/generator.pro
+++ b/src/opengl/util/generator.pro
@@ -9,3 +9,5 @@ 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
index 59d4693c3..e0421c523 100755
--- a/src/opengl/util/glsl_to_include.sh
+++ b/src/opengl/util/glsl_to_include.sh
@@ -1,4 +1,44 @@
#! /bin/sh
+#############################################################################
+##
+## Copyright (C) 2009 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$
+## No Commercial Usage
+## This file contains pre-release code and may not be distributed.
+## You may use this file in accordance with the terms and conditions
+## contained in the Technology Preview License Agreement accompanying
+## this package.
+##
+## GNU Lesser General Public License Usage
+## Alternatively, this file may be used under the terms of the GNU Lesser
+## General Public License version 2.1 as published by the Free Software
+## Foundation and appearing in the file LICENSE.LGPL included in the
+## packaging of this file. Please review the following information to
+## ensure the GNU Lesser General Public License version 2.1 requirements
+## will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+##
+## In addition, as a special exception, 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.
+##
+## If you have questions regarding the use of this file, please contact
+## Nokia at qt-info@nokia.com.
+##
+##
+##
+##
+##
+##
+##
+##
+## $QT_END_LICENSE$
+##
+#############################################################################
# Compile a .glsl file to a file that can be included in a C++ program
USAGE="Usage: $0 <file.glsl>"
diff --git a/src/opengl/util/masks.conf b/src/opengl/util/masks.conf
index 733ac81c7..d853d0b6e 100644
--- a/src/opengl/util/masks.conf
+++ b/src/opengl/util/masks.conf
@@ -1,3 +1,2 @@
FRAGMENT_PROGRAM_MASK_TRAPEZOID_AA trap_exact_aa.glsl
FRAGMENT_PROGRAM_MASK_ELLIPSE_AA ellipse_aa.glsl
-#FRAGMENT_PROGRAM_MASK_ELLIPSE ellipse.glsl
diff --git a/src/opengl/util/pattern_brush.glsl b/src/opengl/util/pattern_brush.glsl
index e070449e0..31702b887 100644
--- a/src/opengl/util/pattern_brush.glsl
+++ b/src/opengl/util/pattern_brush.glsl
@@ -17,9 +17,7 @@ vec4 brush()
coords *= inv_brush_texture_size;
- coords.y = -coords.y;
-
- float alpha = texture2D(brush_texture, coords).r;
+ float alpha = 1.0 - texture2D(brush_texture, coords).r;
return gl_Color * alpha;
}
diff --git a/src/opengl/util/simple_porter_duff.glsl b/src/opengl/util/simple_porter_duff.glsl
index 83aef48c9..4cb0599ac 100644
--- a/src/opengl/util/simple_porter_duff.glsl
+++ b/src/opengl/util/simple_porter_duff.glsl
@@ -7,10 +7,10 @@ vec4 composite(vec4 src, vec4 dst)
result.xyz = porterduff_ab.x * src.xyz * dst.a
+ porterduff_ab.y * dst.xyz * src.a
- + porterduff_xyz.y * src.xyz * (1 - dst.a)
- + porterduff_xyz.z * dst.xyz * (1 - 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 - dst.a), dst.a * (1 - 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/texture_brush.glsl b/src/opengl/util/texture_brush.glsl
index 93865b8af..949825583 100644
--- a/src/opengl/util/texture_brush.glsl
+++ b/src/opengl/util/texture_brush.glsl
@@ -17,7 +17,5 @@ vec4 brush()
coords *= inv_brush_texture_size;
- coords.y = -coords.y;
-
return texture2D(brush_texture, coords);
}
diff --git a/src/opengl/util/trap_exact_aa.glsl b/src/opengl/util/trap_exact_aa.glsl
index b96f87d04..1637f430b 100644
--- a/src/opengl/util/trap_exact_aa.glsl
+++ b/src/opengl/util/trap_exact_aa.glsl
@@ -14,7 +14,7 @@ float quad_aa()
vec2 invA = gl_TexCoord[0].zw;
// transform right line to left to be able to use same calculations for both
- vecX.zw = 2 * gl_FragCoord.x - vecX.zw;
+ vecX.zw = 2.0 * gl_FragCoord.x - vecX.zw;
vec2 topX = vec2(vecX.x, vecX.z);
vec2 bottomX = vec2(vecX.y, vecX.w);
@@ -33,18 +33,18 @@ float quad_aa()
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));
+ 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));
+ excluded, step(topXTemp, right.xx));
excluded = mix(temp, // left < bottom < right (see calculation of temp)
- excluded, step(bottomXTemp, left));
+ excluded, step(bottomXTemp, left.xx));
excluded = mix(vec2(area, area), // right < bottom < top
- excluded, step(bottomXTemp, right));
+ excluded, step(bottomXTemp, right.xx));
excluded *= step(left, topXTemp);
@@ -53,6 +53,6 @@ float quad_aa()
void main()
{
- gl_FragColor = quad_aa();
+ gl_FragColor = quad_aa().xxxx;
}