diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/painting/qdrawutil.cpp | 55 | ||||
-rw-r--r-- | src/gui/painting/qdrawutil.h | 12 | ||||
-rw-r--r-- | src/gui/painting/qpaintengineex.cpp | 25 | ||||
-rw-r--r-- | src/gui/painting/qpaintengineex_p.h | 6 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadermanager.cpp | 59 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadermanager_p.h | 14 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qglengineshadersource_p.h | 20 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 141 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h | 8 |
9 files changed, 292 insertions, 48 deletions
diff --git a/src/gui/painting/qdrawutil.cpp b/src/gui/painting/qdrawutil.cpp index ac3796a..4f17e59 100644 --- a/src/gui/painting/qdrawutil.cpp +++ b/src/gui/painting/qdrawutil.cpp @@ -45,6 +45,7 @@ #include "qapplication.h" #include "qpainter.h" #include "qpalette.h" +#include <private/qpaintengineex_p.h> QT_BEGIN_NAMESPACE @@ -1351,4 +1352,58 @@ void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargin } } +/*! + \struct QDrawPixmapsData + \since 4.6 + \internal + + This structure is used with the qDrawPixmaps() function. + + QPointF point: Specifies the center of the target rectangle. + QRectF source: Specifies the source rectangle in the pixmap passed into the qDrawPixmaps() call. + qreal scaleX: Specifies the horizontal scale of the target rectangle. + qreal scaleY: Specifies the vertical scale of the target rectangle. + qreal rotation: Specifies the rotation of the target rectangle in degrees. + The target rectangle is rotated after scaling. + qreal opacity: Specifies the opacity of the rectangle. +*/ + +/*! + \internal + \since 4.6 + + This function is used to draw \a pixmap, or a sub-rectangle of \a pixmap, at multiple positions + with different scale, rotation and opacity on \a painter. \a drawingData is an array of \a + dataCount elements specifying the parameters used to draw each pixmap instance. + This can be used for example to implement a particle system. +*/ +void qDrawPixmaps(QPainter *painter, const QDrawPixmapsData *drawingData, int dataCount, const QPixmap &pixmap) +{ + QPaintEngine *engine = painter->paintEngine(); + if (!engine) + return; + + if (engine->isExtended()) { + static_cast<QPaintEngineEx *>(engine)->drawPixmaps(drawingData, dataCount, pixmap); + } else { + qreal oldOpacity = painter->opacity(); + QTransform oldTransform = painter->transform(); + + for (int i = 0; i < dataCount; ++i) { + QTransform transform = oldTransform; + transform.translate(drawingData[i].point.x(), drawingData[i].point.y()); + transform.rotate(drawingData[i].rotation); + painter->setOpacity(oldOpacity * drawingData[i].opacity); + painter->setTransform(transform); + + qreal w = drawingData[i].scaleX * drawingData[i].source.width(); + qreal h = drawingData[i].scaleY * drawingData[i].source.height(); + painter->drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, drawingData[i].source); + } + + painter->setOpacity(oldOpacity); + painter->setTransform(oldTransform); + } +} + QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawutil.h b/src/gui/painting/qdrawutil.h index 22a57e9..98a36a7 100644 --- a/src/gui/painting/qdrawutil.h +++ b/src/gui/painting/qdrawutil.h @@ -158,6 +158,18 @@ inline void qDrawBorderPixmap(QPainter *painter, qDrawBorderPixmap(painter, target, margins, pixmap, pixmap.rect(), margins); } +struct QDrawPixmapsData +{ + QPointF point; + QRectF source; + qreal scaleX; + qreal scaleY; + qreal rotation; + qreal opacity; +}; + +Q_GUI_EXPORT void qDrawPixmaps(QPainter *painter, const QDrawPixmapsData *drawingData, int dataCount, const QPixmap &pixmap); + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 60e4df6..2342b9d 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -932,6 +932,31 @@ void QPaintEngineEx::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, con fill(path, brush); } +void QPaintEngineEx::drawPixmaps(const QDrawPixmapsData *drawingData, int dataCount, const QPixmap &pixmap) +{ + qreal oldOpacity = state()->opacity; + QTransform oldTransform = state()->matrix; + + for (int i = 0; i < dataCount; ++i) { + QTransform transform = oldTransform; + transform.translate(drawingData[i].point.x(), drawingData[i].point.y()); + transform.rotate(drawingData[i].rotation); + state()->opacity = oldOpacity * drawingData[i].opacity; + state()->matrix = transform; + opacityChanged(); + transformChanged(); + + qreal w = drawingData[i].scaleX * drawingData[i].source.width(); + qreal h = drawingData[i].scaleY * drawingData[i].source.height(); + drawPixmap(QRectF(-0.5 * w, -0.5 * h, w, h), pixmap, drawingData[i].source); + } + + state()->opacity = oldOpacity; + state()->matrix = oldTransform; + opacityChanged(); + transformChanged(); +} + void QPaintEngineEx::setState(QPainterState *s) { QPaintEngine::state = s; diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 814a0f0..42c1ce9 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -70,7 +70,7 @@ QT_MODULE(Gui) class QPainterState; class QPaintEngineExPrivate; struct StrokeHandler; - +struct QDrawPixmapsData; struct QIntRect { int x1, y1, x2, y2; @@ -133,8 +133,6 @@ public: qreal pts[8]; }; - - #ifndef QT_NO_DEBUG_STREAM QDebug Q_GUI_EXPORT &operator<<(QDebug &, const QVectorPath &path); #endif @@ -198,6 +196,8 @@ public: virtual void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); + virtual void drawPixmaps(const QDrawPixmapsData *drawingData, int dataCount, const QPixmap &pixmap); + virtual void updateState(const QPaintEngineState &state); virtual void setState(QPainterState *s); diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp index fcb20b4..59c50aa 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp +++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp @@ -97,6 +97,7 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context) code[MainVertexShader] = qglslMainVertexShader; code[MainWithTexCoordsVertexShader] = qglslMainWithTexCoordsVertexShader; + code[MainWithTexCoordsAndOpacityVertexShader] = qglslMainWithTexCoordsAndOpacityVertexShader; code[UntransformedPositionVertexShader] = qglslUntransformedPositionVertexShader; code[PositionOnlyVertexShader] = qglslPositionOnlyVertexShader; @@ -119,6 +120,7 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const 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; @@ -285,6 +287,8 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS cached.program->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); if (cached.useTextureCoords) cached.program->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + if (cached.useOpacityAttribute) + cached.program->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR); cached.program->link(); if (!cached.program->isLinked()) { @@ -331,7 +335,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context) : ctx(context), shaderProgNeedsChanging(true), srcPixelType(Qt::NoBrush), - useGlobalOpacity(false), + opacityMode(NoOpacity), maskType(NoMask), compositionMode(QPainter::CompositionMode_SourceOver), customSrcStage(0), @@ -407,12 +411,12 @@ void QGLEngineShaderManager::setSrcPixelType(PixelSrcType type) shaderProgNeedsChanging = true; //### } -void QGLEngineShaderManager::setUseGlobalOpacity(bool useOpacity) +void QGLEngineShaderManager::setOpacityMode(OpacityMode mode) { - if (useGlobalOpacity == useOpacity) + if (opacityMode == mode) return; - useGlobalOpacity = useOpacity; + opacityMode = mode; shaderProgNeedsChanging = true; //### } @@ -564,22 +568,28 @@ bool QGLEngineShaderManager::useCorrectShaderProg() // Choose fragment shader main function: QGLEngineSharedShaders::ShaderName mainFragShaderName; - if (hasCompose && hasMask && useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CMO; - if (hasCompose && hasMask && !useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CM; - if (!hasCompose && hasMask && useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_MO; - if (!hasCompose && hasMask && !useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_M; - if (hasCompose && !hasMask && useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CO; - if (hasCompose && !hasMask && !useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_C; - if (!hasCompose && !hasMask && useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_O; - if (!hasCompose && !hasMask && !useGlobalOpacity) - mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader; + if (opacityMode == AttributeOpacity) { + Q_ASSERT(!hasCompose && !hasMask); + mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_ImageArrays; + } else { + bool useGlobalOpacity = (opacityMode == UniformOpacity); + if (hasCompose && hasMask && useGlobalOpacity) + mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CMO; + if (hasCompose && hasMask && !useGlobalOpacity) + mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CM; + if (!hasCompose && hasMask && useGlobalOpacity) + mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_MO; + if (!hasCompose && hasMask && !useGlobalOpacity) + mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_M; + if (hasCompose && !hasMask && useGlobalOpacity) + mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_CO; + if (hasCompose && !hasMask && !useGlobalOpacity) + mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_C; + if (!hasCompose && !hasMask && useGlobalOpacity) + mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader_O; + if (!hasCompose && !hasMask && !useGlobalOpacity) + mainFragShaderName = QGLEngineSharedShaders::MainFragmentShader; + } requiredProgram.mainFragShader = sharedShaders->compileNamedShader(mainFragShaderName, QGLShader::PartialFragmentShader); @@ -652,12 +662,17 @@ bool QGLEngineShaderManager::useCorrectShaderProg() // Choose vertex shader main function QGLEngineSharedShaders::ShaderName mainVertexShaderName = QGLEngineSharedShaders::InvalidShaderName; - if (texCoords) + if (opacityMode == AttributeOpacity) { + Q_ASSERT(texCoords); + mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader; + } else if (texCoords) { mainVertexShaderName = QGLEngineSharedShaders::MainWithTexCoordsVertexShader; - else + } else { mainVertexShaderName = QGLEngineSharedShaders::MainVertexShader; + } requiredProgram.mainVertexShader = sharedShaders->compileNamedShader(mainVertexShaderName, QGLShader::PartialVertexShader); requiredProgram.useTextureCoords = texCoords; + requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity); // At this point, requiredProgram is fully populated so try to find the program in the cache diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h index fbb6d9c..291d24c 100644 --- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h @@ -247,6 +247,7 @@ struct QGLEngineShaderProg QVector<uint> uniformLocations; bool useTextureCoords; + bool useOpacityAttribute; bool operator==(const QGLEngineShaderProg& other) { // We don't care about the program @@ -277,6 +278,7 @@ 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 QGLEngineSharedShaders : public QObject { @@ -285,6 +287,7 @@ public: enum ShaderName { MainVertexShader, MainWithTexCoordsVertexShader, + MainWithTexCoordsAndOpacityVertexShader, UntransformedPositionVertexShader, PositionOnlyVertexShader, @@ -307,6 +310,7 @@ public: MainFragmentShader_C, MainFragmentShader_O, MainFragmentShader, + MainFragmentShader_ImageArrays, ImageSrcFragmentShader, ImageSrcWithPatternFragmentShader, @@ -406,13 +410,19 @@ public: 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 setUseGlobalOpacity(bool); + void setOpacityMode(OpacityMode); void setMaskType(MaskType); void setCompositionMode(QPainter::CompositionMode); void setCustomStage(QGLCustomShaderStage* stage); @@ -451,7 +461,7 @@ private: // Current state variables which influence the choice of shader: QTransform brushTransform; int srcPixelType; - bool useGlobalOpacity; + OpacityMode opacityMode; MaskType maskType; QPainter::CompositionMode compositionMode; QGLCustomShaderStage* customSrcStage; diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h index 8ae86d3..6712bf6 100644 --- a/src/opengl/gl2paintengineex/qglengineshadersource_p.h +++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h @@ -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;\ @@ -331,6 +345,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; \ diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index f612bc0..12a8ed8 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -366,7 +366,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); @@ -469,7 +469,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 { @@ -479,7 +479,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() 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); @@ -541,7 +541,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms() 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); } @@ -712,7 +712,7 @@ void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& s 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); } @@ -796,9 +796,10 @@ 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); } @@ -824,6 +825,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); @@ -953,7 +964,7 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) { - if (brushTextureDirty && mode != ImageDrawingMode) + if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode) updateBrushTexture(); if (compositionModeDirty) @@ -972,16 +983,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 @@ -993,7 +1010,7 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) opacityUniformDirty = true; } - if (brushUniformsDirty && mode != ImageDrawingMode) + if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode) updateBrushUniforms(); if (shaderMatrixUniformDirty) { @@ -1006,7 +1023,7 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) depthUniformDirty = false; } - if (useGlobalOpacityUniform && opacityUniformDirty) { + if (opacityMode == QGLEngineShaderManager::UniformOpacity && opacityUniformDirty) { shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity); opacityUniformDirty = false; } @@ -1332,7 +1349,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly QColor c = pensBrush.color(); qreal oldOpacity = q->state()->opacity; if (compMode == QPainter::CompositionMode_Source) { - c = premultiplyColor(c, q->state()->opacity); + c = qt_premultiplyColor(c, q->state()->opacity); q->state()->opacity = 1; opacityUniformDirty = true; } @@ -1411,6 +1428,92 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); } +void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmapsData *drawingData, int dataCount, const QPixmap &pixmap) +{ + // Use fallback for extended composition modes. + if (state()->composition_mode > QPainter::CompositionMode_Plus) { + QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap); + return; + } + + Q_D(QGL2PaintEngineEx); + + 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.5 * qSin(drawingData[i].rotation * Q_PI / 180); + qreal c = 0.5 * qCos(drawingData[i].rotation * Q_PI / 180); + + qreal right = drawingData[i].scaleX * drawingData[i].source.width(); + qreal bottom = 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); + } + + ensureActive(); + + 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; + } + + d->transferMode(ImageArrayDrawingMode); + + bool isBitmap = pixmap.isQBitmap(); + bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel() && 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); + + if (isBitmap) { + QColor col = qt_premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity); + d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::PatternColor), col); + } + + glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount); +} + bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) { Q_D(QGL2PaintEngineEx); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index f245945..9d40726 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -61,11 +61,13 @@ #include <private/qglpaintdevice_p.h> #include <private/qglpixmapfilter_p.h> #include <private/qfontengine_p.h> +#include <private/qdatabuffer_p.h> enum EngineMode { ImageDrawingMode, TextDrawingMode, - BrushDrawingMode + BrushDrawingMode, + ImageArrayDrawingMode }; QT_BEGIN_NAMESPACE @@ -126,6 +128,8 @@ public: virtual void drawTextItem(const QPointF &p, const QTextItem &textItem); + virtual void drawPixmaps(const QDrawPixmapsData *drawingData, int dataCount, const QPixmap &pixmap); + Type type() const { return OpenGL2; } void setState(QPainterState *s); @@ -195,7 +199,6 @@ public: // ^ returns whether the current program changed or not inline void useSimpleShader(); - inline QColor premultiplyColor(QColor c, GLfloat opacity); float zValueForRenderText() const; @@ -230,6 +233,7 @@ public: QGL2PEXVertexArray vertexCoordinateArray; QGL2PEXVertexArray textureCoordinateArray; + QDataBuffer<GLfloat> opacityArray; GLfloat staticVertexCoordinateArray[8]; GLfloat staticTextureCoordinateArray[8]; |