244 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
246 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
245 |
247 |
246 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray); |
248 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray); |
247 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray); |
249 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray); |
248 |
250 |
249 pex->shaderManager->blitProgram()->enable(); |
251 pex->shaderManager->blitProgram()->bind(); |
250 pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); |
252 pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); |
251 pex->shaderManager->setDirty(); |
253 pex->shaderManager->setDirty(); |
252 |
254 |
253 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
255 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
254 |
256 |
375 c.setBlueF(c.blueF() * alpha); |
384 c.setBlueF(c.blueF() * alpha); |
376 return c; |
385 return c; |
377 } |
386 } |
378 |
387 |
379 |
388 |
380 void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush) |
389 void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush) |
381 { |
390 { |
|
391 Q_ASSERT(brush.style() != Qt::NoBrush); |
|
392 |
|
393 if (qbrush_fast_equals(currentBrush, brush)) |
|
394 return; |
|
395 |
382 currentBrush = brush; |
396 currentBrush = brush; |
|
397 |
383 brushTextureDirty = true; |
398 brushTextureDirty = true; |
384 brushUniformsDirty = true; |
399 brushUniformsDirty = true; |
385 if (currentBrush->style() == Qt::TexturePattern |
400 if (currentBrush.style() == Qt::TexturePattern |
386 && qHasPixmapTexture(*brush) && brush->texture().isQBitmap()) |
401 && qHasPixmapTexture(brush) && brush.texture().isQBitmap()) |
387 { |
402 { |
388 shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern); |
403 shaderManager->setSrcPixelType(QGLEngineShaderManager::TextureSrcWithPattern); |
389 } else { |
404 } else { |
390 shaderManager->setSrcPixelType(currentBrush->style()); |
405 shaderManager->setSrcPixelType(currentBrush.style()); |
391 } |
406 } |
392 shaderManager->optimiseForBrushTransform(currentBrush->transform()); |
407 shaderManager->optimiseForBrushTransform(currentBrush.transform()); |
393 } |
408 } |
394 |
409 |
395 |
410 |
396 void QGL2PaintEngineExPrivate::useSimpleShader() |
411 void QGL2PaintEngineExPrivate::useSimpleShader() |
397 { |
412 { |
398 shaderManager->simpleProgram()->enable(); |
413 shaderManager->simpleProgram()->bind(); |
399 shaderManager->setDirty(); |
414 shaderManager->setDirty(); |
400 |
415 |
401 if (matrixDirty) |
416 if (matrixDirty) |
402 updateMatrix(); |
417 updateMatrix(); |
403 |
418 |
422 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); |
437 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); |
423 } |
438 } |
424 else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { |
439 else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { |
425 // Gradiant brush: All the gradiants use the same texture |
440 // Gradiant brush: All the gradiants use the same texture |
426 |
441 |
427 const QGradient* g = currentBrush->gradient(); |
442 const QGradient* g = currentBrush.gradient(); |
428 |
443 |
429 // We apply global opacity in the fragment shaders, so we always pass 1.0 |
444 // We apply global opacity in the fragment shaders, so we always pass 1.0 |
430 // for opacity to the cache. |
445 // for opacity to the cache. |
431 GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0); |
446 GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0); |
432 |
447 |
439 updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, q->state()->renderHints & QPainter::SmoothPixmapTransform); |
454 updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, q->state()->renderHints & QPainter::SmoothPixmapTransform); |
440 else |
455 else |
441 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform); |
456 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, q->state()->renderHints & QPainter::SmoothPixmapTransform); |
442 } |
457 } |
443 else if (style == Qt::TexturePattern) { |
458 else if (style == Qt::TexturePattern) { |
444 const QPixmap& texPixmap = currentBrush->texture(); |
459 const QPixmap& texPixmap = currentBrush.texture(); |
445 |
460 |
446 glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); |
461 glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); |
447 QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); |
462 QGLTexture *tex = ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); |
448 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); |
463 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, q->state()->renderHints & QPainter::SmoothPixmapTransform); |
449 textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1; |
464 textureInvertedY = tex->options & QGLContext::InvertedYBindOption ? -1 : 1; |
453 |
468 |
454 |
469 |
455 void QGL2PaintEngineExPrivate::updateBrushUniforms() |
470 void QGL2PaintEngineExPrivate::updateBrushUniforms() |
456 { |
471 { |
457 // qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()"); |
472 // qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()"); |
458 Qt::BrushStyle style = currentBrush->style(); |
473 Qt::BrushStyle style = currentBrush.style(); |
459 |
474 |
460 if (style == Qt::NoBrush) |
475 if (style == Qt::NoBrush) |
461 return; |
476 return; |
462 |
477 |
463 QTransform brushQTransform = currentBrush->transform(); |
478 QTransform brushQTransform = currentBrush.transform(); |
464 |
479 |
465 if (style == Qt::SolidPattern) { |
480 if (style == Qt::SolidPattern) { |
466 QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); |
481 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); |
467 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col); |
482 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col); |
468 } |
483 } |
469 else { |
484 else { |
470 // All other brushes have a transform and thus need the translation point: |
485 // All other brushes have a transform and thus need the translation point: |
471 QPointF translationPoint; |
486 QPointF translationPoint; |
472 |
487 |
473 if (style <= Qt::DiagCrossPattern) { |
488 if (style <= Qt::DiagCrossPattern) { |
474 QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); |
489 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); |
475 |
490 |
476 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); |
491 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); |
477 |
492 |
478 QVector2D halfViewportSize(width*0.5, height*0.5); |
493 QVector2D halfViewportSize(width*0.5, height*0.5); |
479 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); |
494 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); |
480 } |
495 } |
481 else if (style == Qt::LinearGradientPattern) { |
496 else if (style == Qt::LinearGradientPattern) { |
482 const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush->gradient()); |
497 const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush.gradient()); |
483 |
498 |
484 QPointF realStart = g->start(); |
499 QPointF realStart = g->start(); |
485 QPointF realFinal = g->finalStop(); |
500 QPointF realFinal = g->finalStop(); |
486 translationPoint = realStart; |
501 translationPoint = realStart; |
487 |
502 |
497 |
512 |
498 QVector2D halfViewportSize(width*0.5, height*0.5); |
513 QVector2D halfViewportSize(width*0.5, height*0.5); |
499 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); |
514 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); |
500 } |
515 } |
501 else if (style == Qt::ConicalGradientPattern) { |
516 else if (style == Qt::ConicalGradientPattern) { |
502 const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush->gradient()); |
517 const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush.gradient()); |
503 translationPoint = g->center(); |
518 translationPoint = g->center(); |
504 |
519 |
505 GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0; |
520 GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0; |
506 |
521 |
507 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Angle), angle); |
522 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Angle), angle); |
508 |
523 |
509 QVector2D halfViewportSize(width*0.5, height*0.5); |
524 QVector2D halfViewportSize(width*0.5, height*0.5); |
510 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); |
525 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); |
511 } |
526 } |
512 else if (style == Qt::RadialGradientPattern) { |
527 else if (style == Qt::RadialGradientPattern) { |
513 const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush->gradient()); |
528 const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush.gradient()); |
514 QPointF realCenter = g->center(); |
529 QPointF realCenter = g->center(); |
515 QPointF realFocal = g->focalPoint(); |
530 QPointF realFocal = g->focalPoint(); |
516 qreal realRadius = g->radius(); |
531 qreal realRadius = g->radius(); |
517 translationPoint = realFocal; |
532 translationPoint = realFocal; |
518 |
533 |
526 |
541 |
527 QVector2D halfViewportSize(width*0.5, height*0.5); |
542 QVector2D halfViewportSize(width*0.5, height*0.5); |
528 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); |
543 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); |
529 } |
544 } |
530 else if (style == Qt::TexturePattern) { |
545 else if (style == Qt::TexturePattern) { |
531 const QPixmap& texPixmap = currentBrush->texture(); |
546 const QPixmap& texPixmap = currentBrush.texture(); |
532 |
547 |
533 if (qHasPixmapTexture(*currentBrush) && currentBrush->texture().isQBitmap()) { |
548 if (qHasPixmapTexture(currentBrush) && currentBrush.texture().isQBitmap()) { |
534 QColor col = qt_premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity); |
549 QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); |
535 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); |
550 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); |
536 } |
551 } |
537 |
552 |
538 QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 * textureInvertedY / texPixmap.height()); |
553 QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height()); |
539 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::InvertedTextureSize), invertedTextureSize); |
554 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::InvertedTextureSize), invertedTextureSize); |
540 |
555 |
541 QVector2D halfViewportSize(width*0.5, height*0.5); |
556 QVector2D halfViewportSize(width*0.5, height*0.5); |
542 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); |
557 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize); |
543 } |
558 } |
548 QTransform matrix = q->state()->matrix; |
563 QTransform matrix = q->state()->matrix; |
549 matrix.translate(brushOrigin.x(), brushOrigin.y()); |
564 matrix.translate(brushOrigin.x(), brushOrigin.y()); |
550 |
565 |
551 QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y()); |
566 QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y()); |
552 QTransform gl_to_qt(1, 0, 0, -1, 0, height); |
567 QTransform gl_to_qt(1, 0, 0, -1, 0, height); |
553 QTransform inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate; |
568 QTransform inv_matrix; |
|
569 if (style == Qt::TexturePattern && textureInvertedY == -1) |
|
570 inv_matrix = gl_to_qt * (QTransform(1, 0, 0, -1, 0, currentBrush.texture().height()) * brushQTransform * matrix).inverted() * translate; |
|
571 else |
|
572 inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate; |
554 |
573 |
555 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTransform), inv_matrix); |
574 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTransform), inv_matrix); |
556 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT); |
575 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT); |
557 } |
576 } |
558 brushUniformsDirty = false; |
577 brushUniformsDirty = false; |
574 // |
593 // |
575 // We expand out the multiplication to save the cost of a full 4x4 |
594 // We expand out the multiplication to save the cost of a full 4x4 |
576 // matrix multiplication as most of the components are trivial. |
595 // matrix multiplication as most of the components are trivial. |
577 const QTransform& transform = q->state()->matrix; |
596 const QTransform& transform = q->state()->matrix; |
578 |
597 |
579 if (mode == TextDrawingMode) { |
598 qreal wfactor = 2.0 / width; |
580 // Text drawing mode is only used for non-scaling transforms |
599 qreal hfactor = -2.0 / height; |
581 pmvMatrix[0][0] = 2.0 / width; |
600 |
582 pmvMatrix[0][1] = 0.0; |
601 pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13(); |
583 pmvMatrix[0][2] = 0.0; |
602 pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13(); |
584 pmvMatrix[0][3] = 0.0; |
603 pmvMatrix[0][2] = 0.0; |
585 pmvMatrix[1][0] = 0.0; |
604 pmvMatrix[0][3] = transform.m13(); |
586 pmvMatrix[1][1] = -2.0 / height; |
605 pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23(); |
587 pmvMatrix[1][2] = 0.0; |
606 pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23(); |
588 pmvMatrix[1][3] = 0.0; |
607 pmvMatrix[1][2] = 0.0; |
589 pmvMatrix[2][0] = 0.0; |
608 pmvMatrix[1][3] = transform.m23(); |
590 pmvMatrix[2][1] = 0.0; |
609 pmvMatrix[2][0] = 0.0; |
591 pmvMatrix[2][2] = -1.0; |
610 pmvMatrix[2][1] = 0.0; |
592 pmvMatrix[2][3] = 0.0; |
611 pmvMatrix[2][2] = -1.0; |
593 pmvMatrix[3][0] = pmvMatrix[0][0] * qRound(transform.dx()) - 1.0; |
612 pmvMatrix[2][3] = 0.0; |
594 pmvMatrix[3][1] = pmvMatrix[1][1] * qRound(transform.dy()) + 1.0; |
613 pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33(); |
595 pmvMatrix[3][2] = 0.0; |
614 pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33(); |
596 pmvMatrix[3][3] = 1.0; |
615 pmvMatrix[3][2] = 0.0; |
597 |
616 pmvMatrix[3][3] = transform.m33(); |
598 inverseScale = 1; |
617 |
599 } else { |
618 // 1/10000 == 0.0001, so we have good enough res to cover curves |
600 qreal wfactor = 2.0 / width; |
619 // that span the entire widget... |
601 qreal hfactor = -2.0 / height; |
620 inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), |
602 |
621 qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), |
603 pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13(); |
622 qreal(0.0001)); |
604 pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13(); |
|
605 pmvMatrix[0][2] = 0.0; |
|
606 pmvMatrix[0][3] = transform.m13(); |
|
607 pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23(); |
|
608 pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23(); |
|
609 pmvMatrix[1][2] = 0.0; |
|
610 pmvMatrix[1][3] = transform.m23(); |
|
611 pmvMatrix[2][0] = 0.0; |
|
612 pmvMatrix[2][1] = 0.0; |
|
613 pmvMatrix[2][2] = -1.0; |
|
614 pmvMatrix[2][3] = 0.0; |
|
615 pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33(); |
|
616 pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33(); |
|
617 pmvMatrix[3][2] = 0.0; |
|
618 pmvMatrix[3][3] = transform.m33(); |
|
619 |
|
620 // 1/10000 == 0.0001, so we have good enough res to cover curves |
|
621 // that span the entire widget... |
|
622 inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), |
|
623 qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), |
|
624 qreal(0.0001)); |
|
625 } |
|
626 |
623 |
627 matrixDirty = false; |
624 matrixDirty = false; |
628 |
625 |
629 // The actual data has been updated so both shader program's uniforms need updating |
626 // The actual data has been updated so both shader program's uniforms need updating |
630 simpleShaderMatrixUniformDirty = true; |
627 simpleShaderMatrixUniformDirty = true; |
802 glDisableVertexAttribArray(QT_OPACITY_ATTR); |
799 glDisableVertexAttribArray(QT_OPACITY_ATTR); |
803 |
800 |
804 lastTexture = GLuint(-1); |
801 lastTexture = GLuint(-1); |
805 } |
802 } |
806 |
803 |
807 if (mode == TextDrawingMode) |
|
808 matrixDirty = true; |
|
809 |
|
810 if (newMode == TextDrawingMode) { |
804 if (newMode == TextDrawingMode) { |
811 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
805 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
812 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
806 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
813 |
807 |
814 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); |
808 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); |
815 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); |
809 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); |
816 |
|
817 matrixDirty = true; |
|
818 } |
810 } |
819 |
811 |
820 if (newMode == ImageDrawingMode) { |
812 if (newMode == ImageDrawingMode) { |
821 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
813 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
822 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
814 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
854 const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); |
870 const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); |
855 |
871 |
856 // Check to see if there's any hints |
872 // Check to see if there's any hints |
857 if (path.shape() == QVectorPath::RectangleHint) { |
873 if (path.shape() == QVectorPath::RectangleHint) { |
858 QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y()); |
874 QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y()); |
859 prepareForDraw(currentBrush->isOpaque()); |
875 prepareForDraw(currentBrush.isOpaque()); |
860 composite(rect); |
876 composite(rect); |
861 } else if (path.shape() == QVectorPath::EllipseHint |
877 } else if (path.isConvex()) { |
862 || path.shape() == QVectorPath::ConvexPolygonHint) |
878 |
863 { |
879 if (path.isCacheable()) { |
864 vertexCoordinateArray.clear(); |
880 QVectorPath::CacheEntry *data = path.lookupCacheData(q); |
865 vertexCoordinateArray.addPath(path, inverseScale, false); |
881 QGL2PEVectorPathCache *cache; |
866 prepareForDraw(currentBrush->isOpaque()); |
882 |
867 drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); |
883 if (data) { |
|
884 cache = (QGL2PEVectorPathCache *) data->data; |
|
885 // Check if scale factor is exceeded for curved paths and generate curves if so... |
|
886 if (path.isCurved()) { |
|
887 qreal scaleFactor = cache->iscale / inverseScale; |
|
888 if (scaleFactor < 0.5 || scaleFactor > 2.0) { |
|
889 #ifdef QT_OPENGL_CACHE_AS_VBOS |
|
890 glDeleteBuffers(1, &cache->vbo); |
|
891 cache->vbo = 0; |
|
892 #else |
|
893 qFree(cache->vertices); |
|
894 #endif |
|
895 cache->vertexCount = 0; |
|
896 } |
|
897 } |
|
898 } else { |
|
899 cache = new QGL2PEVectorPathCache; |
|
900 cache->vertexCount = 0; |
|
901 data = const_cast<QVectorPath &>(path).addCacheData(q, cache, qopengl2paintengine_cleanup_vectorpath); |
|
902 } |
|
903 |
|
904 // Flatten the path at the current scale factor and fill it into the cache struct. |
|
905 if (!cache->vertexCount) { |
|
906 vertexCoordinateArray.clear(); |
|
907 vertexCoordinateArray.addPath(path, inverseScale, false); |
|
908 int vertexCount = vertexCoordinateArray.vertexCount(); |
|
909 int floatSizeInBytes = vertexCount * 2 * sizeof(float); |
|
910 cache->vertexCount = vertexCount; |
|
911 cache->primitiveType = GL_TRIANGLE_FAN; |
|
912 cache->iscale = inverseScale; |
|
913 #ifdef QT_OPENGL_CACHE_AS_VBOS |
|
914 glGenBuffers(1, &cache->vbo); |
|
915 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); |
|
916 glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW); |
|
917 #else |
|
918 cache->vertices = (float *) qMalloc(floatSizeInBytes); |
|
919 memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes); |
|
920 #endif |
|
921 } |
|
922 |
|
923 prepareForDraw(currentBrush.isOpaque()); |
|
924 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
|
925 #ifdef QT_OPENGL_CACHE_AS_VBOS |
|
926 glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); |
|
927 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0); |
|
928 #else |
|
929 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, cache->vertices); |
|
930 #endif |
|
931 glDrawArrays(cache->primitiveType, 0, cache->vertexCount); |
|
932 |
|
933 } else { |
|
934 // printf(" - Marking path as cachable...\n"); |
|
935 // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable |
|
936 // ### Remove before release... |
|
937 static bool do_vectorpath_cache = qgetenv("QT_OPENGL_NO_PATH_CACHE").isEmpty(); |
|
938 if (do_vectorpath_cache) |
|
939 path.makeCacheable(); |
|
940 vertexCoordinateArray.clear(); |
|
941 vertexCoordinateArray.addPath(path, inverseScale, false); |
|
942 prepareForDraw(currentBrush.isOpaque()); |
|
943 drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); |
|
944 } |
|
945 |
868 } else { |
946 } else { |
869 // The path is too complicated & needs the stencil technique |
947 // The path is too complicated & needs the stencil technique |
870 vertexCoordinateArray.clear(); |
948 vertexCoordinateArray.clear(); |
871 vertexCoordinateArray.addPath(path, inverseScale, false); |
949 vertexCoordinateArray.addPath(path, inverseScale, false); |
872 |
950 |
962 // Inc. for front-facing triangle |
1041 // Inc. for front-facing triangle |
963 glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP); |
1042 glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP); |
964 // Dec. for back-facing "holes" |
1043 // Dec. for back-facing "holes" |
965 glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP); |
1044 glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP); |
966 glStencilMask(~GL_STENCIL_HIGH_BIT); |
1045 glStencilMask(~GL_STENCIL_HIGH_BIT); |
967 drawVertexArrays(data, stops, GL_TRIANGLE_FAN); |
1046 drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); |
968 |
1047 |
969 if (q->state()->clipTestEnabled) { |
1048 if (q->state()->clipTestEnabled) { |
970 // Clear high bit of stencil outside of path |
1049 // Clear high bit of stencil outside of path |
971 glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); |
1050 glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); |
972 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); |
1051 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); |
974 composite(bounds); |
1053 composite(bounds); |
975 } |
1054 } |
976 } else if (mode == OddEvenFillMode) { |
1055 } else if (mode == OddEvenFillMode) { |
977 glStencilMask(GL_STENCIL_HIGH_BIT); |
1056 glStencilMask(GL_STENCIL_HIGH_BIT); |
978 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit |
1057 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit |
979 drawVertexArrays(data, stops, GL_TRIANGLE_FAN); |
1058 drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); |
980 |
1059 |
981 } else { // TriStripStrokeFillMode |
1060 } else { // TriStripStrokeFillMode |
982 Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops |
1061 Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops |
983 glStencilMask(GL_STENCIL_HIGH_BIT); |
1062 glStencilMask(GL_STENCIL_HIGH_BIT); |
984 #if 0 |
1063 #if 0 |
1133 |
1212 |
1134 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
1213 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
1135 } |
1214 } |
1136 |
1215 |
1137 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans. |
1216 // Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans. |
1138 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, const QVector<int> *stops, |
1217 void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount, |
1139 GLenum primitive) |
1218 GLenum primitive) |
1140 { |
1219 { |
1141 // Now setup the pointer to the vertex array: |
1220 // Now setup the pointer to the vertex array: |
1142 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
1221 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
1143 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); |
1222 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); |
1144 |
1223 |
1145 int previousStop = 0; |
1224 int previousStop = 0; |
1146 foreach(int stop, *stops) { |
1225 for (int i=0; i<stopCount; ++i) { |
|
1226 int stop = stops[i]; |
1147 /* |
1227 /* |
1148 qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1); |
1228 qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1); |
1149 for (int i=previousStop; i<stop; ++i) |
1229 for (int i=previousStop; i<stop; ++i) |
1150 qDebug(" %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y); |
1230 qDebug(" %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y); |
1151 */ |
1231 */ |
1199 return; |
1279 return; |
1200 if (!d->inRenderText) |
1280 if (!d->inRenderText) |
1201 ensureActive(); |
1281 ensureActive(); |
1202 |
1282 |
1203 QOpenGL2PaintEngineState *s = state(); |
1283 QOpenGL2PaintEngineState *s = state(); |
1204 bool doOffset = !(s->renderHints & QPainter::Antialiasing) && style == Qt::SolidPattern; |
1284 bool doOffset = !(s->renderHints & QPainter::Antialiasing) && |
|
1285 (style == Qt::SolidPattern) && |
|
1286 !d->multisamplingAlwaysEnabled; |
1205 |
1287 |
1206 if (doOffset) { |
1288 if (doOffset) { |
1207 d->temporaryTransform = s->matrix; |
1289 d->temporaryTransform = s->matrix; |
1208 QTransform tx = QTransform::fromTranslate(.49, .49); |
1290 QTransform tx = QTransform::fromTranslate(.49, .49); |
1209 s->matrix = s->matrix * tx; |
1291 s->matrix = s->matrix * tx; |
1210 d->matrixDirty = true; |
1292 d->matrixDirty = true; |
1211 } |
1293 } |
1212 |
1294 |
1213 d->setBrush(&brush); |
1295 d->setBrush(brush); |
1214 d->fill(path); |
1296 d->fill(path); |
1215 |
1297 |
1216 if (doOffset) { |
1298 if (doOffset) { |
1217 s->matrix = d->temporaryTransform; |
1299 s->matrix = d->temporaryTransform; |
1218 d->matrixDirty = true; |
1300 d->matrixDirty = true; |
1219 } |
1301 } |
1220 } |
1302 } |
|
1303 |
|
1304 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp |
|
1305 |
1221 |
1306 |
1222 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) |
1307 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) |
1223 { |
1308 { |
1224 Q_D(QGL2PaintEngineEx); |
1309 Q_D(QGL2PaintEngineEx); |
1225 |
1310 |
1227 const QBrush &penBrush = qpen_brush(pen); |
1312 const QBrush &penBrush = qpen_brush(pen); |
1228 if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) |
1313 if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) |
1229 return; |
1314 return; |
1230 |
1315 |
1231 QOpenGL2PaintEngineState *s = state(); |
1316 QOpenGL2PaintEngineState *s = state(); |
|
1317 if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) { |
|
1318 // QTriangulatingStroker class is not meant to support cosmetically sheared strokes. |
|
1319 QPaintEngineEx::stroke(path, pen); |
|
1320 return; |
|
1321 } |
1232 |
1322 |
1233 ensureActive(); |
1323 ensureActive(); |
1234 |
1324 |
1235 bool doOffset = !(s->renderHints & QPainter::Antialiasing); |
1325 bool doOffset = !(s->renderHints & QPainter::Antialiasing) && !d->multisamplingAlwaysEnabled; |
1236 if (doOffset) { |
1326 if (doOffset) { |
1237 d->temporaryTransform = s->matrix; |
1327 d->temporaryTransform = s->matrix; |
1238 QTransform tx = QTransform::fromTranslate(0.49, .49); |
1328 QTransform tx = QTransform::fromTranslate(0.49, .49); |
1239 s->matrix = s->matrix * tx; |
1329 s->matrix = s->matrix * tx; |
1240 d->matrixDirty = true; |
1330 d->matrixDirty = true; |
1241 } |
1331 } |
1242 |
1332 |
1243 bool opaque = penBrush.isOpaque() && s->opacity > 0.99; |
1333 bool opaque = penBrush.isOpaque() && s->opacity > 0.99; |
1244 d->setBrush(&penBrush); |
1334 d->setBrush(penBrush); |
1245 d->transferMode(BrushDrawingMode); |
1335 d->transferMode(BrushDrawingMode); |
1246 |
1336 |
1247 // updateMatrix() is responsible for setting the inverse scale on |
1337 // updateMatrix() is responsible for setting the inverse scale on |
1248 // the strokers, so we need to call it here and not wait for |
1338 // the strokers, so we need to call it here and not wait for |
1249 // prepareForDraw() down below. |
1339 // prepareForDraw() down below. |
1289 extra = extra * d->inverseScale; |
1380 extra = extra * d->inverseScale; |
1290 |
1381 |
1291 QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); |
1382 QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); |
1292 |
1383 |
1293 d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2, |
1384 d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2, |
1294 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode); |
1385 0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode); |
1295 |
1386 |
1296 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); |
1387 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); |
1297 |
1388 |
1298 // Pass when any bit is set, replace stencil value with 0 |
1389 // Pass when any bit is set, replace stencil value with 0 |
1299 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); |
1390 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); |
1431 ensureActive(); |
1522 ensureActive(); |
1432 QOpenGL2PaintEngineState *s = state(); |
1523 QOpenGL2PaintEngineState *s = state(); |
1433 |
1524 |
1434 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); |
1525 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); |
1435 |
1526 |
1436 bool drawCached = true; |
1527 QTransform::TransformationType txtype = s->matrix.type(); |
1437 |
1528 |
1438 if (s->matrix.type() > QTransform::TxTranslate) |
1529 float det = s->matrix.determinant(); |
1439 drawCached = false; |
1530 bool drawCached = txtype < QTransform::TxProject; |
1440 |
1531 |
1441 // don't try to cache huge fonts |
1532 // don't try to cache huge fonts or vastly transformed fonts |
1442 if (ti.fontEngine->fontDef.pixelSize * qSqrt(s->matrix.determinant()) >= 64) |
1533 const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; |
|
1534 if (pixelSize * pixelSize * qAbs(det) >= 64 * 64 || det < 0.25f || det > 4.f) |
1443 drawCached = false; |
1535 drawCached = false; |
1444 |
1536 |
1445 QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 |
1537 QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 |
1446 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) |
1538 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) |
1447 : d->glyphCacheType; |
1539 : d->glyphCacheType; |
1448 |
1540 |
1449 if (d->inRenderText) |
1541 if (d->inRenderText || txtype > QTransform::TxTranslate) |
1450 glyphType = QFontEngineGlyphCache::Raster_A8; |
1542 glyphType = QFontEngineGlyphCache::Raster_A8; |
1451 |
1543 |
1452 if (glyphType == QFontEngineGlyphCache::Raster_RGBMask |
1544 if (glyphType == QFontEngineGlyphCache::Raster_RGBMask |
1453 && state()->composition_mode != QPainter::CompositionMode_Source |
1545 && state()->composition_mode != QPainter::CompositionMode_Source |
1454 && state()->composition_mode != QPainter::CompositionMode_SourceOver) |
1546 && state()->composition_mode != QPainter::CompositionMode_SourceOver) |
1466 |
1558 |
1467 void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, |
1559 void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, |
1468 const QTextItemInt &ti) |
1560 const QTextItemInt &ti) |
1469 { |
1561 { |
1470 Q_Q(QGL2PaintEngineEx); |
1562 Q_Q(QGL2PaintEngineEx); |
1471 QOpenGL2PaintEngineState *s = q->state(); |
|
1472 |
1563 |
1473 QVarLengthArray<QFixedPoint> positions; |
1564 QVarLengthArray<QFixedPoint> positions; |
1474 QVarLengthArray<glyph_t> glyphs; |
1565 QVarLengthArray<glyph_t> glyphs; |
1475 QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); |
1566 QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); |
1476 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); |
1567 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); |
1477 |
1568 |
1478 QGLTextureGlyphCache *cache = |
1569 QGLTextureGlyphCache *cache = |
1479 (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, s->matrix); |
1570 (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform()); |
1480 |
1571 |
1481 if (!cache || cache->cacheType() != glyphType) { |
1572 if (!cache || cache->cacheType() != glyphType) { |
1482 cache = new QGLTextureGlyphCache(ctx, glyphType, s->matrix); |
1573 cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); |
1483 ti.fontEngine->setGlyphCache(ctx, cache); |
1574 ti.fontEngine->setGlyphCache(ctx, cache); |
1484 } |
1575 } |
1485 |
1576 |
1486 cache->setPaintEnginePrivate(this); |
1577 cache->setPaintEnginePrivate(this); |
1487 cache->populate(ti, glyphs, positions); |
1578 cache->populate(ti, glyphs, positions); |
1517 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); |
1608 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); |
1518 if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr) |
1609 if (textureCoordinateArray.data() != oldTextureCoordinateDataPtr) |
1519 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); |
1610 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); |
1520 |
1611 |
1521 QBrush pensBrush = q->state()->pen.brush(); |
1612 QBrush pensBrush = q->state()->pen.brush(); |
1522 setBrush(&pensBrush); |
1613 setBrush(pensBrush); |
1523 |
1614 |
1524 if (inRenderText) |
1615 if (inRenderText) |
1525 prepareDepthRangeForRenderText(); |
1616 prepareDepthRangeForRenderText(); |
1526 |
1617 |
1527 if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { |
1618 if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) { |
1728 d->matrixDirty = true; |
1819 d->matrixDirty = true; |
1729 d->compositionModeDirty = true; |
1820 d->compositionModeDirty = true; |
1730 d->opacityUniformDirty = true; |
1821 d->opacityUniformDirty = true; |
1731 d->needsSync = true; |
1822 d->needsSync = true; |
1732 d->use_system_clip = !systemClip().isEmpty(); |
1823 d->use_system_clip = !systemClip().isEmpty(); |
|
1824 d->currentBrush = QBrush(); |
1733 |
1825 |
1734 d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); |
1826 d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); |
1735 d->stencilClean = true; |
1827 d->stencilClean = true; |
1736 |
1828 |
1737 // Calling begin paint should make the correct context current. So, any |
1829 // Calling begin paint should make the correct context current. So, any |
1738 // code which calls into GL or otherwise needs a current context *must* |
1830 // code which calls into GL or otherwise needs a current context *must* |
1739 // go after beginPaint: |
1831 // go after beginPaint: |
1740 d->device->beginPaint(); |
1832 d->device->beginPaint(); |
1741 |
1833 |
1742 #if !defined(QT_OPENGL_ES_2) |
1834 #if !defined(QT_OPENGL_ES_2) |
1743 bool success = qt_resolve_version_2_0_functions(d->ctx); |
1835 bool success = qt_resolve_version_2_0_functions(d->ctx) |
|
1836 && qt_resolve_buffer_extensions(d->ctx); |
1744 Q_ASSERT(success); |
1837 Q_ASSERT(success); |
1745 Q_UNUSED(success); |
1838 Q_UNUSED(success); |
1746 #endif |
1839 #endif |
1747 |
1840 |
1748 d->shaderManager = new QGLEngineShaderManager(d->ctx); |
1841 d->shaderManager = new QGLEngineShaderManager(d->ctx); |
2084 maxClip = 1; |
2189 maxClip = 1; |
2085 |
2190 |
2086 q->state()->rectangleClip = use_system_clip ? systemClip.boundingRect() : QRect(0, 0, width, height); |
2191 q->state()->rectangleClip = use_system_clip ? systemClip.boundingRect() : QRect(0, 0, width, height); |
2087 updateClipScissorTest(); |
2192 updateClipScissorTest(); |
2088 |
2193 |
2089 if (systemClip.numRects() == 1) { |
2194 if (systemClip.rectCount() == 1) { |
2090 if (systemClip.boundingRect() == QRect(0, 0, width, height)) |
2195 if (systemClip.boundingRect() == QRect(0, 0, width, height)) |
2091 use_system_clip = false; |
2196 use_system_clip = false; |
2092 #ifndef QT_GL_NO_SCISSOR_TEST |
2197 #ifndef QT_GL_NO_SCISSOR_TEST |
2093 // scissoring takes care of the system clip |
2198 // scissoring takes care of the system clip |
2094 return; |
2199 return; |