diff options
Diffstat (limited to 'src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp')
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 195 |
1 files changed, 146 insertions, 49 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 13efbda..bcc6bdb 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -81,6 +81,8 @@ #include "qglengineshadermanager_p.h" #include "qgl2pexvertexarray_p.h" +#include "qtriangulatingstroker_p.h" + #include <QDebug> QT_BEGIN_NAMESPACE @@ -572,7 +574,6 @@ void QGL2PaintEngineExPrivate::updateMatrix() // // 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) { @@ -628,6 +629,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); } @@ -838,28 +842,6 @@ void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) mode = newMode; } -void QGL2PaintEngineExPrivate::drawOutline(const QVectorPath& path) -{ - 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; - } - - prepareForDraw(currentBrush->isOpaque()); - drawVertexArrays(vertexCoordinateArray, GL_LINE_STRIP); -} - - // Assumes everything is configured for the brush you want to use void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) { @@ -922,8 +904,14 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) } -void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) +void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, + int count, + const QVector<int> *stops, + const QGLRect &bounds, + StencilFillMode mode) { + Q_ASSERT(count || stops); + // qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); glStencilMask(0xff); // Enable stencil writes @@ -955,19 +943,20 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve } #endif - if (useWindingFill) { + 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(vertexArray.boundingRect()); + 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(vertexArray.boundingRect()); + composite(bounds); } // Inc. for front-facing triangle @@ -975,19 +964,43 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve // Dec. for back-facing "holes" glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP); glStencilMask(~GL_STENCIL_HIGH_BIT); - drawVertexArrays(vertexArray, GL_TRIANGLE_FAN); + drawVertexArrays(data, stops, 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(vertexArray.boundingRect()); + composite(bounds); } - } else { + } else if (mode == OddEvenFillMode) { + glStencilMask(GL_STENCIL_HIGH_BIT); + glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit + drawVertexArrays(data, stops, 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 - drawVertexArrays(vertexArray, GL_TRIANGLE_FAN); + 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 @@ -1122,14 +1135,15 @@ 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, const QVector<int> *stops, + 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()) { + foreach(int stop, *stops) { /* qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1); for (int i=previousStop; i<stop; ++i) @@ -1180,12 +1194,29 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush) { Q_D(QGL2PaintEngineEx); - if (qbrush_style(brush) == 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; + + if (doOffset) { + d->temporaryTransform = s->matrix; + QTransform tx = QTransform::fromTranslate(.49, .49); + s->matrix = s->matrix * tx; + d->matrixDirty = true; + } + d->setBrush(&brush); d->fill(path); + + if (doOffset) { + s->matrix = d->temporaryTransform; + d->matrixDirty = true; + } } void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) @@ -1197,23 +1228,89 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) return; + QOpenGL2PaintEngineState *s = state(); + ensureActive(); - qreal penWidth = qpen_widthf(pen); - if ( (pen.isCosmetic() && (penStyle == Qt::SolidLine)) && (penWidth < 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); + if (doOffset) { + d->temporaryTransform = s->matrix; + QTransform tx = QTransform::fromTranslate(0.49, .49); + s->matrix = s->matrix * tx; + d->matrixDirty = true; + } - if (penWidth < 0.01f) - glLineWidth(1.0); - else - glLineWidth(penWidth); + bool opaque = penBrush.isOpaque() && s->opacity > 0.99; + d->setBrush(&penBrush); + d->transferMode(BrushDrawingMode); + + // updateMatrix() is responsible for setting the inverse scale on + // the strokers, so we need to call it here and not wait for + // prepareForDraw() down below. + d->updateMatrix(); + + if (penStyle == Qt::SolidLine) { + d->stroker.process(path, pen); + + } else { // Some sort of dash + d->dasher.process(path, pen); + + QVectorPath dashStroke(d->dasher.points(), + d->dasher.elementCount(), + d->dasher.elementTypes()); + d->stroker.process(dashStroke, pen); + } + + + QGLContext *ctx = d->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); - d->drawOutline(path); - } else - return QPaintEngineEx::stroke(path, pen); + 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, 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() { } @@ -1542,7 +1639,7 @@ void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int d 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); |