📄 qpaintengine_opengl.cpp
字号:
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();#ifdef Q_WS_QWS glOrthof(0, sz.width(), sz.height(), 0, -999999, 999999);#else glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999);#endif glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glEnable(GL_BLEND); d->composition_mode = QPainter::CompositionMode_SourceOver;#ifndef Q_WS_QWS bool shared_ctx = qgl_share_reg()->checkSharing(d->drawable.context(), d->shader_ctx); if (!shared_ctx) { if (d->shader_ctx) { d->shader_ctx->makeCurrent(); glBindTexture(GL_TEXTURE_1D, 0); glDeleteTextures(1, &d->grad_palette); if (has_frag_program && d->use_fragment_programs) { glDeleteTextures(1, &d->drawable_texture); d->deleteFragmentPrograms(); } d->drawable.context()->makeCurrent(); } d->shader_ctx = d->drawable.context(); glGenTextures(1, &d->grad_palette); qt_mask_texture_cache()->clearCache(); if (has_frag_program) { d->use_fragment_programs = d->createFragmentPrograms(); if (!d->use_fragment_programs) { d->deleteFragmentPrograms(); qWarning() << "QOpenGLPaintEngine: Failed to create fragment programs."; } } gccaps &= ~(RadialGradientFill | ConicalGradientFill | LinearGradientFill | PatternBrush | BlendModes); if (d->use_fragment_programs) gccaps |= (RadialGradientFill | ConicalGradientFill | LinearGradientFill | PatternBrush | BlendModes); else if (QGLExtensions::glExtensions & QGLExtensions::MirroredRepeat) gccaps |= LinearGradientFill; } if (d->use_fragment_programs && (!shared_ctx || sz.width() > d->drawable_texture_size.width() || sz.height() > d->drawable_texture_size.height())) { // delete old texture if size has increased, otherwise it was deleted earlier if (shared_ctx) glDeleteTextures(1, &d->drawable_texture); glGenTextures(1, &d->drawable_texture); glBindTexture(GL_TEXTURE_2D, d->drawable_texture); QSize adjusted_size(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height())); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, adjusted_size.width(), adjusted_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); d->drawable_texture_size = adjusted_size; }#endif setDirty(QPaintEngine::DirtyPen); setDirty(QPaintEngine::DirtyBrush); setDirty(QPaintEngine::DirtyCompositionMode);#ifdef Q_WS_QWS // XXX: needed only if painting on a widget? updateClipRegion(QRegion(), Qt::NoClip);#endif return true;}bool QOpenGLPaintEngine::end(){ Q_D(QOpenGLPaintEngine); d->flushDrawQueue(); d->offscreen.end(); glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix();#ifndef Q_WS_QWS glMatrixMode(GL_PROJECTION); glLoadMatrixd(&d->projection_matrix[0][0]); glPopAttrib(); glPopClientAttrib();#endif#ifndef Q_WS_QWS d->drawable.swapBuffers();#endif d->drawable.doneCurrent(); qt_mask_texture_cache()->maintainCache(); return true;}void QOpenGLPaintEngine::updateState(const QPaintEngineState &state){ Q_D(QOpenGLPaintEngine); QPaintEngine::DirtyFlags flags = state.state(); bool update_fast_pen = false; if (flags & DirtyOpacity) { update_fast_pen = true; d->opacity = state.opacity(); if (d->opacity > 1.0f) d->opacity = 1.0f; if (d->opacity < 0.f) d->opacity = 0.f; // force update flags |= DirtyPen; flags |= DirtyBrush; } if (flags & DirtyTransform) { update_fast_pen = true; updateMatrix(state.transform()); // brush setup depends on transform state if (state.brush().style() != Qt::NoBrush) flags |= DirtyBrush; } if (flags & DirtyPen) { update_fast_pen = true; updatePen(state.pen()); } if (flags & (DirtyBrush | DirtyBrushOrigin)) { updateBrush(state.brush(), state.brushOrigin()); } if (flags & DirtyFont) { updateFont(state.font()); } if (state.state() & DirtyClipEnabled) { if (state.isClipEnabled()) updateClipRegion(painter()->clipRegion(), Qt::ReplaceClip); else updateClipRegion(QRegion(), Qt::NoClip); } if (flags & DirtyClipPath) { updateClipRegion(QRegion(state.clipPath().toFillPolygon().toPolygon(), state.clipPath().fillRule()), state.clipOperation()); } if (flags & DirtyClipRegion) { updateClipRegion(state.clipRegion(), state.clipOperation()); } if (flags & DirtyHints) { updateRenderHints(state.renderHints()); } if (flags & DirtyCompositionMode) { updateCompositionMode(state.compositionMode()); } if (update_fast_pen) { Q_D(QOpenGLPaintEngine); qreal pen_width = d->cpen.widthF(); d->has_fast_pen = ((pen_width == 0 || (pen_width <= 1 && d->txop <= QTransform::TxTranslate)) || d->cpen.isCosmetic()) && d->cpen.style() == Qt::SolidLine && d->cpen.isSolid(); }}void QOpenGLPaintEnginePrivate::setInvMatrixData(const QTransform &inv_matrix){ inv_matrix_data[0][0] = inv_matrix.m11(); inv_matrix_data[1][0] = inv_matrix.m21(); inv_matrix_data[2][0] = inv_matrix.m31(); inv_matrix_data[0][1] = inv_matrix.m12(); inv_matrix_data[1][1] = inv_matrix.m22(); inv_matrix_data[2][1] = inv_matrix.m32(); inv_matrix_data[0][2] = inv_matrix.m13(); inv_matrix_data[1][2] = inv_matrix.m23(); inv_matrix_data[2][2] = inv_matrix.m33();}void QOpenGLPaintEnginePrivate::updateGradient(const QBrush &brush, const QRectF &bounds){#ifdef Q_WS_QWS Q_UNUSED(brush); Q_UNUSED(bounds);#else bool has_mirrored_repeat = QGLExtensions::glExtensions & QGLExtensions::MirroredRepeat; Qt::BrushStyle style = brush.style(); if (has_mirrored_repeat && style == Qt::LinearGradientPattern) { const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient()); QTransform m = brush.transform(); QPointF realStart = g->start(); QPointF realFinal = g->finalStop(); if (g->coordinateMode() == QGradient::ObjectBoundingMode) { qreal sx = bounds.x() + realStart.x() * bounds.width(); qreal sy = bounds.y() + realStart.y() * bounds.height(); qreal fx = bounds.x() + realFinal.x() * bounds.width(); qreal fy = bounds.y() + realFinal.y() * bounds.height(); realStart = QPointF(sx, sy); realFinal = QPointF(fx, fy); } QPointF start = m.map(realStart); QPointF stop; if (qFuzzyCompare(m.m11(), m.m22()) && m.m12() == 0.0 && m.m21() == 0.0) { // It is a simple uniform scale and/or translation stop = m.map(realFinal); } else { // It is not enough to just transform the endpoints. // We have to make sure the _pattern_ is transformed correctly. qreal odx = realFinal.x() - realStart.x(); qreal ody = realFinal.y() - realStart.y(); // nx, ny and dx, dy are normal and gradient direction after transform: qreal nx = m.m11()*ody - m.m21()*odx; qreal ny = m.m12()*ody - m.m22()*odx; qreal dx = m.m11()*odx + m.m21()*ody; qreal dy = m.m12()*odx + m.m22()*ody; qreal lx = 1.0/(dx - dy*nx/ny); qreal ly = 1.0/(dy - dx*ny/nx); qreal l = 1.0/sqrt(lx*lx+ly*ly); stop = start + QPointF(-ny, nx) * l/sqrt(nx*nx+ny*ny); } float tr[4], f; tr[0] = stop.x() - start.x(); tr[1] = stop.y() - start.y(); f = 1.0 / (tr[0]*tr[0] + tr[1]*tr[1]); tr[0] *= f; tr[1] *= f; tr[2] = 0; tr[3] = -(start.x()*tr[0] + start.y()*tr[1]); setGLBrush(Qt::white); qt_glColor4ubv(brush_color); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); glTexGenfv(GL_S, GL_OBJECT_PLANE, tr); } if (use_fragment_programs) { if (style == Qt::RadialGradientPattern) { const QRadialGradient *g = static_cast<const QRadialGradient *>(brush.gradient()); QPointF realCenter = g->center(); QPointF realFocal = g->focalPoint(); qreal realRadius = g->radius(); if (g->coordinateMode() == QGradient::ObjectBoundingMode) { qreal x = bounds.x() + realCenter.x() * bounds.width(); qreal y = bounds.y() + realCenter.y() * bounds.height(); realCenter = QPointF(x, y); x = bounds.x() + realFocal.x() * bounds.width(); y = bounds.y() + realFocal.y() * bounds.height(); realFocal = QPointF(x, y); realRadius = qMin(bounds.x() + bounds.width() * realRadius, bounds.y() + bounds.height() * realRadius); } 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; setInvMatrixData(inv_matrix); fmp_data[0] = realCenter.x() - realFocal.x(); fmp_data[1] = realCenter.y() - realFocal.y(); fmp2_m_radius2_data[0] = -fmp_data[0] * fmp_data[0] - fmp_data[1] * fmp_data[1] + realRadius * realRadius; } else if (style == Qt::ConicalGradientPattern) { const QConicalGradient *g = static_cast<const QConicalGradient *>(brush.gradient()); QPointF realCenter = g->center(); if (g->coordinateMode() == QGradient::ObjectBoundingMode) { qreal x = bounds.x() + bounds.width() * realCenter.x(); qreal y = bounds.y() + bounds.height() * realCenter.y(); realCenter = QPointF(x, y); } 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; setInvMatrixData(inv_matrix); angle_data[0] = -(g->angle() * 2 * Q_PI) / 360.0; } else if (style == Qt::LinearGradientPattern) { const QLinearGradient *g = static_cast<const QLinearGradient *>(brush.gradient()); QPointF realStart = g->start(); QPointF realFinal = g->finalStop(); if (g->coordinateMode() == QGradient::ObjectBoundingMode) { qreal sx = bounds.x() + realStart.x() * bounds.width(); qreal sy = bounds.y() + realStart.y() * bounds.height(); qreal fx = bounds.x() + realFinal.x() * bounds.width(); qreal fy = bounds.y() + realFinal.y() * bounds.height(); realStart = QPointF(sx, sy); realFinal = QPointF(fx, fy); } 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; setInvMatrixData(inv_matrix); QPointF l = realFinal - realStart; linear_data[0] = l.x(); linear_data[1] = l.y(); 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; setInvMatrixData(inv_matrix); } } if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { createGradientPaletteTexture(*brush.gradient()); }#endif}class QOpenGLTessellator : public QTessellator{public: QOpenGLTessellator() {} ~QOpenGLTessellator() { } QGLTrapezoid toGLTrapezoid(const Trapezoid &trap);};QGLTrapezoid QOpenGLTessellator::toGLTrapezoid(const Trapezoid &trap){ QGLTrapezoid t; t.top = Q27Dot5ToDouble(trap.top); t.bottom = Q27Dot5ToDouble(trap.bottom); Q27Dot5 y = trap.topLeft->y - trap.bottomLeft->y; qreal topLeftY = Q27Dot5ToDouble(trap.topLeft->y); qreal tx = Q27Dot5ToDouble(trap.topLeft->x); qreal m = (-tx + Q27Dot5ToDouble(trap.bottomLeft->x)) / Q27Dot5ToDouble(y); t.topLeftX = tx + m * (topLeftY - t.top); t.bottomLeftX = tx + m * (topLeftY - t.bottom); y = trap.topRight->y - trap.bottomRight->y; qreal topRightY = Q27Dot5ToDouble(trap.topRight->y); tx = Q27Dot5ToDouble(trap.topRight->x); m = (-tx + Q27Dot5ToDouble(trap.bottomRight->x)) / Q27Dot5ToDouble(y); t.topRightX = tx + m * (topRightY - Q27Dot5ToDouble(trap.top)); t.bottomRightX = tx + m * (topRightY - Q27Dot5ToDouble(trap.bottom)); return t;}class QOpenGLImmediateModeTessellator : public QOpenGLTessellator{public: void addTrap(const Trapezoid &trap); void tessellate(const QPointF *points, int nPoints, bool winding) { trapezoids.reserve(trapezoids.size() + nPoints); setWinding(winding); QTessellator::tessellate(points, nPoints); } QVector<QGLTrapezoid> trapezoids;};void QOpenGLImmediateModeTessellator::addTrap(const Trapezoid &trap){ trapezoids.append(toGLTrapezoid(trap));}#ifndef Q_WS_QWSstatic void drawTrapezoid(const QGLTrapezoid &trap, const qreal offscreenHeight, QGLContext *ctx){ qreal minX = qMin(trap.topLeftX, trap.bottomLeftX); qreal maxX = qMax(trap.topRightX, trap.bottomRightX); if (qFuzzyCompare(trap.top, trap.bottom) || qFuzzyCompare(minX, maxX) || qFuzzyCompare(trap.topLeftX, trap.topRightX) && qFuzzyCompare(trap.bottomLeftX, trap.bottomRightX))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -