📄 qpaintengine_opengl.cpp
字号:
return; const qreal xpadding = 1.0; const qreal ypadding = 1.0; qreal topDist = offscreenHeight - trap.top; qreal bottomDist = offscreenHeight - trap.bottom; qreal reciprocal = bottomDist / (bottomDist - topDist); qreal leftB = trap.bottomLeftX + (trap.topLeftX - trap.bottomLeftX) * reciprocal; qreal rightB = trap.bottomRightX + (trap.topRightX - trap.bottomRightX) * reciprocal; const bool topZero = qFuzzyCompare(topDist, 0); reciprocal = topZero ? 1.0 / bottomDist : 1.0 / topDist; qreal leftA = topZero ? (trap.bottomLeftX - leftB) * reciprocal : (trap.topLeftX - leftB) * reciprocal; qreal rightA = topZero ? (trap.bottomRightX - rightB) * reciprocal : (trap.topRightX - rightB) * reciprocal; qreal invLeftA = qFuzzyCompare(leftA, qreal(0.0)) ? 0.0 : 1.0 / leftA; qreal invRightA = qFuzzyCompare(rightA, qreal(0.0)) ? 0.0 : 1.0 / rightA; // fragment program needs the negative of invRightA as it mirrors the line glTexCoord4f(topDist, bottomDist, invLeftA, -invRightA); glMultiTexCoord4f(GL_TEXTURE1, leftA, leftB, rightA, rightB); qreal topY = trap.top - ypadding; qreal bottomY = trap.bottom + ypadding; qreal bounds_bottomLeftX = leftA * (offscreenHeight - bottomY) + leftB; qreal bounds_bottomRightX = rightA * (offscreenHeight - bottomY) + rightB; qreal bounds_topLeftX = leftA * (offscreenHeight - topY) + leftB; qreal bounds_topRightX = rightA * (offscreenHeight - topY) + rightB; QPointF leftNormal(1, -leftA); leftNormal /= sqrt(leftNormal.x() * leftNormal.x() + leftNormal.y() * leftNormal.y()); QPointF rightNormal(1, -rightA); rightNormal /= sqrt(rightNormal.x() * rightNormal.x() + rightNormal.y() * rightNormal.y()); qreal left_padding = xpadding / qAbs(leftNormal.x()); qreal right_padding = xpadding / qAbs(rightNormal.x()); glVertex2d(bounds_topLeftX - left_padding, topY); glVertex2d(bounds_topRightX + right_padding, topY); glVertex2d(bounds_bottomRightX + right_padding, bottomY); glVertex2d(bounds_bottomLeftX - left_padding, bottomY); glTexCoord4f(0.0f, 0.0f, 0.0f, 1.0f);}#endif // !Q_WS_QWSclass QOpenGLTrapezoidToArrayTessellator : public QOpenGLTessellator{public: QOpenGLTrapezoidToArrayTessellator() : vertices(0), allocated(0), size(0) {} ~QOpenGLTrapezoidToArrayTessellator() { free(vertices); } float *vertices; int allocated; int size; QRectF bounds; void addTrap(const Trapezoid &trap); void tessellate(const QPointF *points, int nPoints, bool winding) { size = 0; setWinding(winding); bounds = QTessellator::tessellate(points, nPoints); }};void QOpenGLTrapezoidToArrayTessellator::addTrap(const Trapezoid &trap){#ifndef Q_WS_QWS if (size > allocated - 8) {#else if (size > allocated - 12) {#endif allocated = qMax(2*allocated, 512); vertices = (float *)realloc(vertices, allocated * sizeof(float)); } QGLTrapezoid t = toGLTrapezoid(trap);#ifndef Q_WS_QWS vertices[size++] = t.topLeftX; vertices[size++] = t.top; vertices[size++] = t.topRightX; vertices[size++] = t.top; vertices[size++] = t.bottomRightX; vertices[size++] = t.bottom; vertices[size++] = t.bottomLeftX; vertices[size++] = t.bottom;#else vertices[size++] = t.topLeftX; vertices[size++] = t.top; vertices[size++] = t.topRightX; vertices[size++] = t.top; vertices[size++] = t.bottomRightX; vertices[size++] = t.bottom; vertices[size++] = t.bottomLeftX; vertices[size++] = t.bottom; vertices[size++] = t.topLeftX; vertices[size++] = t.top; vertices[size++] = t.bottomRightX; vertices[size++] = t.bottom;#endif}void QOpenGLPaintEnginePrivate::fillPolygon_dev(const QPointF *polygonPoints, int pointCount, Qt::FillRule fill){ QOpenGLTrapezoidToArrayTessellator tessellator; tessellator.tessellate(polygonPoints, pointCount, fill == Qt::WindingFill); DEBUG_ONCE qDebug() << "QOpenGLPaintEnginePrivate: Drawing polygon with" << pointCount << "points using fillPolygon_dev"; setGradientOps(cbrush, tessellator.bounds); bool fast_style = current_style == Qt::LinearGradientPattern || current_style == Qt::SolidPattern;#ifndef Q_WS_QWS GLenum geometry_mode = GL_QUADS;#else GLenum geometry_mode = GL_TRIANGLES;#endif if (use_fragment_programs && !(fast_style && has_fast_composition_mode)) { composite(geometry_mode, tessellator.vertices, tessellator.size / 2); } else { glVertexPointer(2, GL_FLOAT, 0, tessellator.vertices); glEnableClientState(GL_VERTEX_ARRAY); glDrawArrays(geometry_mode, 0, tessellator.size/2); glDisableClientState(GL_VERTEX_ARRAY); }}inline void QOpenGLPaintEnginePrivate::lineToStencil(qreal x, qreal y){ tess_points.add(QPointF(x, y)); if (x > max_x) max_x = x; else if (x < min_x) min_x = x; if (y > max_y) max_y = y; else if (y < min_y) min_y = y;}inline void QOpenGLPaintEnginePrivate::curveToStencil(const QPointF &cp1, const QPointF &cp2, const QPointF &ep){ qreal inverseScaleHalf = inverseScale / 2; QBezier beziers[32]; beziers[0] = QBezier::fromPoints(tess_points.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 lineToStencil(b->x4, b->y4); --b; } else { // split, second half of the polygon goes lower into the stack b->split(b+1, b); ++b; } }}void QOpenGLPaintEnginePrivate::pathToVertexArrays(const QPainterPath &path){ const QPainterPath::Element &first = path.elementAt(0); min_x = max_x = first.x; min_y = max_y = first.y; tess_points.reset(); tess_points_stops.clear(); lineToStencil(first.x, first.y); for (int i=1; i<path.elementCount(); ++i) { const QPainterPath::Element &e = path.elementAt(i); switch (e.type) { case QPainterPath::MoveToElement: tess_points_stops.append(tess_points.size()); lineToStencil(e.x, e.y); break; case QPainterPath::LineToElement: lineToStencil(e.x, e.y); break; case QPainterPath::CurveToElement: curveToStencil(e, path.elementAt(i+1), path.elementAt(i+2)); i+=2; break; default: break; } } lineToStencil(first.x, first.y); tess_points_stops.append(tess_points.size());}void QOpenGLPaintEnginePrivate::drawVertexArrays(){ glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_DOUBLE, 0, tess_points.data()); int previous_stop = 0; foreach(int stop, tess_points_stops) { glDrawArrays(GL_TRIANGLE_FAN, previous_stop, stop-previous_stop); previous_stop = stop; } glDisableClientState(GL_VERTEX_ARRAY);}void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule){ glStencilMask(~0); // Enable stencil. glEnable(GL_STENCIL_TEST); // Disable color writes. glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); GLuint stencilMask = 0; if (fillRule == Qt::OddEvenFill) { stencilMask = 1; // Enable stencil writes. glStencilMask(stencilMask); // Set stencil xor mode. glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Disable stencil func. glStencilFunc(GL_ALWAYS, 0, ~0); drawVertexArrays(); } else if (fillRule == Qt::WindingFill) { stencilMask = ~0; if (has_stencil_face_ext) { QGL_FUNC_CONTEXT; glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT); glActiveStencilFaceEXT(GL_BACK); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT); glStencilFunc(GL_ALWAYS, 0, ~0); glActiveStencilFaceEXT(GL_FRONT); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT); glStencilFunc(GL_ALWAYS, 0, ~0); drawVertexArrays(); glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); } else { glStencilFunc(GL_ALWAYS, 0, ~0); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT); drawVertexArrays(); glCullFace(GL_FRONT); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT); drawVertexArrays(); glDisable(GL_CULL_FACE); } } // Enable color writes. glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilMask(0); setGradientOps(cbrush, QRectF(QPointF(min_x, min_y), QSizeF(max_x - min_x, max_y - min_y))); bool fast_fill = has_fast_composition_mode && (current_style == Qt::LinearGradientPattern || current_style == Qt::SolidPattern); if (use_fragment_programs && !fast_fill) { DEBUG_ONCE qDebug() << "QOpenGLPaintEnginePrivate: Drawing polygon using stencil method (fragment programs)"; QRectF rect(QPointF(min_x, min_y), QSizeF(max_x - min_x, max_y - min_y)); // Enable stencil func. glStencilFunc(GL_NOTEQUAL, 0, stencilMask); composite(rect); } else { DEBUG_ONCE qDebug() << "QOpenGLPaintEnginePrivate: Drawing polygon using stencil method (no fragment programs)"; // Enable stencil func. glStencilFunc(GL_NOTEQUAL, 0, stencilMask);#ifndef Q_WS_QWS glBegin(GL_QUADS); glVertex2f(min_x, min_y); glVertex2f(max_x, min_y); glVertex2f(max_x, max_y); glVertex2f(min_x, max_y); glEnd();#endif } glStencilMask(~0); glStencilFunc(GL_ALWAYS, 0, 0); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // clear all stencil values to 0 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);#ifndef Q_WS_QWS glBegin(GL_QUADS); glVertex2f(min_x, min_y); glVertex2f(max_x, min_y); glVertex2f(max_x, max_y); glVertex2f(min_x, max_y); glEnd();#endif glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Disable stencil writes. glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilMask(0); glDisable(GL_STENCIL_TEST);}void QOpenGLPaintEnginePrivate::fillPath(const QPainterPath &path){ if (path.isEmpty()) return; if (use_stencil_method && !high_quality_antialiasing) { pathToVertexArrays(path); fillVertexArray(path.fillRule()); return; } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); if (high_quality_antialiasing) drawOffscreenPath(path); else { QPolygonF poly = path.toFillPolygon(matrix); fillPolygon_dev(poly.data(), poly.count(), path.fillRule()); } glMatrixMode(GL_MODELVIEW);#ifndef Q_WS_QWS GLdouble mat[4][4];#else GLfloat mat[4][4];#endif QTransform mtx = matrix; mat[0][0] = mtx.m11(); mat[0][1] = mtx.m12(); mat[0][2] = 0; mat[0][3] = mtx.m13(); mat[1][0] = mtx.m21(); mat[1][1] = mtx.m22(); mat[1][2] = 0; mat[1][3] = mtx.m23(); mat[2][0] = 0; mat[2][1] = 0; mat[2][2] = 1; mat[2][3] = 0; mat[3][0] = mtx.dx(); mat[3][1] = mtx.dy(); mat[3][2] = 0; mat[3][3] = 1;#ifndef Q_WS_QWS glLoadMatrixd(&mat[0][0]);#else glLoadMatrixf(&mat[0][0]);#endif}void QOpenGLPaintEngine::updatePen(const QPen &pen){ Q_D(QOpenGLPaintEngine); Qt::PenStyle pen_style = pen.style(); d->pen_brush_style = pen.brush().style(); d->cpen = pen; d->has_pen = (pen_style != Qt::NoPen); if (pen.isCosmetic()) { GLfloat width = pen.widthF() == 0.0f ? 1.0f : pen.widthF(); glLineWidth(width); glPointSize(width); } if (d->pen_brush_style >= Qt::LinearGradientPattern && d->pen_brush_style <= Qt::ConicalGradientPattern) { d->setGLPen(Qt::white); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -