source: trunk/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp@ 104

Last change on this file since 104 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 41.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtOpenGL module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*
43 When the active program changes, we need to update it's uniforms.
44 We could track state for each program and only update stale uniforms
45 - Could lead to lots of overhead if there's a lot of programs
46 We could update all the uniforms when the program changes
47 - Could end up updating lots of uniforms which don't need updating
48
49 Updating uniforms should be cheap, so the overhead of updating up-to-date
50 uniforms should be minimal. It's also less complex.
51
52 Things which _may_ cause a different program to be used:
53 - Change in brush/pen style
54 - Change in painter opacity
55 - Change in composition mode
56
57 Whenever we set a mode on the shader manager - it needs to tell us if it had
58 to switch to a different program.
59
60 The shader manager should only switch when we tell it to. E.g. if we set a new
61 brush style and then switch to transparent painter, we only want it to compile
62 and use the correct program when we really need it.
63*/
64
65
66#include "qpaintengineex_opengl2_p.h"
67
68#include <string.h> //for memcpy
69#include <qmath.h>
70
71#include <private/qgl_p.h>
72#include <private/qmath_p.h>
73#include <private/qpaintengineex_p.h>
74#include <QPaintEngine>
75#include <private/qpainter_p.h>
76#include <private/qfontengine_p.h>
77#include <private/qtextureglyphcache_p.h>
78
79#include "qglgradientcache_p.h"
80#include "qglpexshadermanager_p.h"
81#include "qgl2pexvertexarray_p.h"
82
83
84extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp
85
86
87#include <QDebug>
88
89
90static const GLuint QT_VERTEX_COORDS_ATTR = 0;
91static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
92static const GLuint QT_BRUSH_TEXTURE_UNIT = 0;
93
94class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate
95{
96 Q_DECLARE_PUBLIC(QGL2PaintEngineEx)
97public:
98 QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) :
99 q(q_ptr),
100 width(0), height(0),
101 ctx(0),
102 currentBrush( &(q->state()->brush) ),
103 inverseScale(1),
104 shaderManager(0)
105 { }
106
107 ~QGL2PaintEngineExPrivate();
108
109 void updateBrushTexture();
110 void updateBrushUniforms();
111 void updateMatrix();
112 void updateCompositionMode();
113 void updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform);
114
115 void setBrush(const QBrush* brush);
116
117 void drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight);
118
119 void fill(const QVectorPath &path);
120 void drawOutline(const QVectorPath& path);
121
122 void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive);
123 // ^ draws whatever is in the vertex array
124 void composite(const QGLRect& boundingRect);
125 // ^ Composites the bounding rect onto dest buffer
126 void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill);
127 // ^ Calls drawVertexArrays to render into stencil buffer
128 void cleanStencilBuffer(const QGLRect& area);
129
130 void prepareForDraw();
131
132 inline void useSimpleShader();
133 inline QColor premultiplyColor(QColor c, GLfloat opacity);
134
135 QGL2PaintEngineEx* q;
136
137 //### Move into QGLDrawable
138 int width, height;
139 QGLContext* ctx;
140
141 // Dirty flags
142 bool matrixDirty; // Implies matrix uniforms are also dirty
143 bool compositionModeDirty;
144 bool brushTextureDirty;
145 bool brushUniformsDirty;
146 bool simpleShaderMatrixUniformDirty;
147 bool brushShaderMatrixUniformDirty;
148 bool imageShaderMatrixUniformDirty;
149 bool textShaderMatrixUniformDirty;
150 bool stencilBuferDirty;
151
152 const QBrush* currentBrush; // May not be the state's brush!
153
154 GLfloat inverseScale;
155
156 QGL2PEXVertexArray pathVertexArray;
157
158 GLfloat pmvMatrix[4][4];
159
160 QGLPEXShaderManager* shaderManager;
161
162 // Clipping & state stuff stolen from QOpenGLPaintEngine:
163 void updateDepthClip();
164 uint use_system_clip : 1;
165};
166
167
168////////////////////////////////// Private Methods //////////////////////////////////////////
169
170QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
171{
172 if (shaderManager) {
173 delete shaderManager;
174 shaderManager = 0;
175 }
176}
177
178void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform)
179{
180 glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
181
182 if (smoothPixmapTransform) {
183 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
184 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
185 } else {
186 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
187 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
188 }
189 glTexParameterf(target, GL_TEXTURE_WRAP_S, wrapMode);
190 glTexParameterf(target, GL_TEXTURE_WRAP_T, wrapMode);
191}
192
193
194QColor QGL2PaintEngineExPrivate::premultiplyColor(QColor c, GLfloat opacity)
195{
196 uint alpha = qRound(c.alpha() * opacity);
197 return QColor ( ((c.red() * alpha + 128) >> 8),
198 ((c.green() * alpha + 128) >> 8),
199 ((c.blue() * alpha + 128) >> 8),
200 alpha);
201}
202
203
204void QGL2PaintEngineExPrivate::setBrush(const QBrush* brush)
205{
206 currentBrush = brush;
207 brushTextureDirty = true;
208 brushUniformsDirty = true;
209 shaderManager->setBrushStyle(currentBrush->style());
210 shaderManager->setAffineOnlyBrushTransform(currentBrush->transform().isAffine());
211}
212
213
214// Unless this gets used elsewhere, it's probably best to merge it into fillStencilWithVertexArray
215void QGL2PaintEngineExPrivate::useSimpleShader()
216{
217 shaderManager->simpleShader()->use();
218
219 if (matrixDirty)
220 updateMatrix();
221
222 if (simpleShaderMatrixUniformDirty) {
223 shaderManager->simpleShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
224 simpleShaderMatrixUniformDirty = false;
225 }
226}
227
228
229Q_GLOBAL_STATIC(QGLGradientCache, qt_opengl_gradient_cache)
230
231void QGL2PaintEngineExPrivate::updateBrushTexture()
232{
233// qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()");
234 Qt::BrushStyle style = currentBrush->style();
235
236 if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) {
237 // Get the image data for the pattern
238 QImage texImage = qt_imageForBrush(style, true);
239
240 glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
241 ctx->d_func()->bindTexture(texImage, GL_TEXTURE_2D, GL_RGBA, true);
242 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
243 }
244 else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
245 // Gradiant brush: All the gradiants use the same texture
246
247 const QGradient* g = currentBrush->gradient();
248
249 // We apply global opacity in the fragment shaders, so we always pass 1.0
250 // for opacity to the cache.
251 GLuint texId = qt_opengl_gradient_cache()->getBuffer(*g, 1.0, ctx);
252
253 if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient)
254 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
255 else if (g->spread() == QGradient::ReflectSpread)
256 updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, true);
257 else
258 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, true);
259
260 glBindTexture(GL_TEXTURE_2D, texId);
261 }
262 else if (style == Qt::TexturePattern) {
263 const QPixmap& texPixmap = currentBrush->texture();
264
265 glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
266 ctx->d_func()->bindTexture(texPixmap, GL_TEXTURE_2D, GL_RGBA, true);
267 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
268 }
269 brushTextureDirty = false;
270}
271
272
273void QGL2PaintEngineExPrivate::updateBrushUniforms()
274{
275// qDebug("QGL2PaintEngineExPrivate::updateBrushUniforms()");
276 Qt::BrushStyle style = currentBrush->style();
277
278 if (style == Qt::NoBrush)
279 return;
280
281 GLfloat opacity = 1.0;
282 if (q->state()->opacity < 0.99f)
283 opacity = (GLfloat)q->state()->opacity;
284 bool setOpacity = true;
285
286 QTransform brushQTransform = currentBrush->transform();
287
288 if (style == Qt::SolidPattern) {
289 QColor col = premultiplyColor(currentBrush->color(), opacity);
290 shaderManager->brushShader()->uniforms()[QLatin1String("fragmentColor")] = col;
291 setOpacity = false;
292 }
293 else {
294 // All other brushes have a transform and thus need the translation point:
295 QPointF translationPoint;
296
297 if (style <= Qt::DiagCrossPattern) {
298 translationPoint = q->state()->brushOrigin;
299
300 QColor col = premultiplyColor(currentBrush->color(), opacity);
301
302 shaderManager->brushShader()->uniforms()[QLatin1String("patternColor")] = col;
303 setOpacity = false; //So code below doesn't try to set the opacity uniform
304
305 QGLVec2 halfViewportSize = { width*0.5, height*0.5 };
306 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;
307 }
308 else if (style == Qt::LinearGradientPattern) {
309 const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush->gradient());
310
311 QPointF realStart = g->start();
312 QPointF realFinal = g->finalStop();
313 translationPoint = realStart;
314
315 QPointF l = realFinal - realStart;
316
317 // ###
318 QGLVec3 linearData = {
319 l.x(),
320 l.y(),
321 1.0f / (l.x() * l.x() + l.y() * l.y())
322 };
323
324 shaderManager->brushShader()->uniforms()[QLatin1String("linearData")] = linearData;
325
326 QGLVec2 halfViewportSize = { width*0.5, height*0.5 };
327 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;
328 }
329 else if (style == Qt::ConicalGradientPattern) {
330 const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush->gradient());
331 translationPoint = g->center();
332
333 GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0;
334
335 shaderManager->brushShader()->uniforms()[QLatin1String("angle")] = angle;
336
337 QGLVec2 halfViewportSize = { width*0.5, height*0.5 };
338 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;
339 }
340 else if (style == Qt::RadialGradientPattern) {
341 const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush->gradient());
342 QPointF realCenter = g->center();
343 QPointF realFocal = g->focalPoint();
344 qreal realRadius = g->radius();
345 translationPoint = realFocal;
346
347 QPointF fmp = realCenter - realFocal;
348 shaderManager->brushShader()->uniforms()[QLatin1String("fmp")] = fmp;
349
350 GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius;
351 shaderManager->brushShader()->uniforms()[QLatin1String("fmp2_m_radius2")] = fmp2_m_radius2;
352
353 shaderManager->brushShader()->uniforms()[QLatin1String("inverse_2_fmp2_m_radius2")] =
354 GLfloat(1.0 / (2.0*fmp2_m_radius2));
355
356 QGLVec2 halfViewportSize = { width*0.5, height*0.5 };
357 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;
358 }
359 else if (style == Qt::TexturePattern) {
360 translationPoint = q->state()->brushOrigin;
361
362 const QPixmap& texPixmap = currentBrush->texture();
363
364 QSizeF invertedTextureSize( 1.0 / texPixmap.width(), 1.0 / texPixmap.height() );
365 shaderManager->brushShader()->uniforms()[QLatin1String("invertedTextureSize")] = invertedTextureSize;
366
367 QGLVec2 halfViewportSize = { width*0.5, height*0.5 };
368 shaderManager->brushShader()->uniforms()[QLatin1String("halfViewportSize")] = halfViewportSize;
369 }
370 else
371 qWarning("QGL2PaintEngineEx: Unimplemented fill style");
372
373 QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y());
374 QTransform gl_to_qt(1, 0, 0, -1, 0, height);
375 QTransform inv_matrix = gl_to_qt * (brushQTransform * q->state()->matrix).inverted() * translate;
376
377 shaderManager->brushShader()->uniforms()[QLatin1String("brushTransform")] = inv_matrix;
378 shaderManager->brushShader()->uniforms()[QLatin1String("brushTexture")] = QT_BRUSH_TEXTURE_UNIT;
379
380 if (setOpacity)
381 shaderManager->brushShader()->uniforms()[QLatin1String("opacity")] = opacity;
382 }
383 brushUniformsDirty = false;
384}
385
386
387// This assumes the shader manager has already setup the correct shader program
388void QGL2PaintEngineExPrivate::updateMatrix()
389{
390// qDebug("QGL2PaintEngineExPrivate::updateMatrix()");
391
392 // We setup the Projection matrix to be the equivilant of glOrtho(0, w, h, 0, -1, 1):
393 GLfloat P[4][4] = {
394 {2.0/width, 0.0, 0.0, -1.0},
395 {0.0, -2.0/height, 0.0, 1.0},
396 {0.0, 0.0, -1.0, 0.0},
397 {0.0, 0.0, 0.0, 1.0}
398 };
399
400 // Use the (3x3) transform for the Model~View matrix:
401 const QTransform& transform = q->state()->matrix;
402 GLfloat MV[4][4] = {
403 {transform.m11(), transform.m21(), 0.0, transform.dx() + 0.5},
404 {transform.m12(), transform.m22(), 0.0, transform.dy() + 0.5},
405 {0.0, 0.0, 1.0, 0.0},
406 {transform.m13(), transform.m23(), 0.0, transform.m33()}
407 };
408
409 // NOTE: OpenGL ES works with column-major matrices, so when we multiply the matrices,
410 // we also transpose them ready for GL.
411 for (int row = 0; row < 4; ++row) {
412 for (int col = 0; col < 4; ++col) {
413 pmvMatrix[col][row] = 0.0;
414 for (int n = 0; n < 4; ++n)
415 pmvMatrix[col][row] += P[row][n] * MV[n][col];
416 }
417 }
418
419 // 1/10000 == 0.0001, so we have good enough res to cover curves
420 // that span the entire widget...
421 inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())),
422 qMax(qAbs(transform.m12()), qAbs(transform.m21())) ),
423 qreal(0.0001));
424
425 matrixDirty = false;
426
427 // The actual data has been updated so both shader program's uniforms need updating
428 simpleShaderMatrixUniformDirty = true;
429 brushShaderMatrixUniformDirty = true;
430 imageShaderMatrixUniformDirty = true;
431 textShaderMatrixUniformDirty = true;
432}
433
434
435void QGL2PaintEngineExPrivate::updateCompositionMode()
436{
437 // NOTE: The entire paint engine works on pre-multiplied data - which is why some of these
438 // composition modes look odd.
439// qDebug() << "QGL2PaintEngineExPrivate::updateCompositionMode() - Setting GL composition mode for " << q->state()->composition_mode;
440 switch(q->state()->composition_mode) {
441 case QPainter::CompositionMode_SourceOver:
442 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
443 break;
444 case QPainter::CompositionMode_DestinationOver:
445 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE);
446 break;
447 case QPainter::CompositionMode_Clear:
448 glBlendFunc(GL_ZERO, GL_ZERO);
449 break;
450 case QPainter::CompositionMode_Source:
451 glBlendFunc(GL_ONE, GL_ZERO);
452 break;
453 case QPainter::CompositionMode_Destination:
454 glBlendFunc(GL_ZERO, GL_ONE);
455 break;
456 case QPainter::CompositionMode_SourceIn:
457 glBlendFunc(GL_DST_ALPHA, GL_ZERO);
458 break;
459 case QPainter::CompositionMode_DestinationIn:
460 glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
461 break;
462 case QPainter::CompositionMode_SourceOut:
463 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);
464 break;
465 case QPainter::CompositionMode_DestinationOut:
466 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
467 break;
468 case QPainter::CompositionMode_SourceAtop:
469 glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
470 break;
471 case QPainter::CompositionMode_DestinationAtop:
472 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA);
473 break;
474 case QPainter::CompositionMode_Xor:
475 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
476 break;
477 case QPainter::CompositionMode_Plus:
478 glBlendFunc(GL_ONE, GL_ONE);
479 break;
480 default:
481 qWarning("Unsupported composition mode");
482 break;
483 }
484
485 compositionModeDirty = false;
486}
487
488
489void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& src, int txtWidth, int txtHeight)
490{
491// qDebug("QGL2PaintEngineExPrivate::drawImage()");
492
493 // We have a shader specifically for drawPixmap/drawImage...
494 shaderManager->imageShader()->use();
495
496 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
497
498 if (compositionModeDirty)
499 updateCompositionMode();
500
501 if (matrixDirty)
502 updateMatrix();
503
504 if (imageShaderMatrixUniformDirty) {
505 shaderManager->imageShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
506 imageShaderMatrixUniformDirty = false;
507 }
508
509 shaderManager->imageShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT;
510
511// if (q->state()->opacity < 0.99f)
512 shaderManager->imageShader()->uniforms()[QLatin1String("opacity")] = (GLfloat)q->state()->opacity;
513
514 GLfloat vertexCoords[] = {
515 dest.left, dest.top,
516 dest.left, dest.bottom,
517 dest.right, dest.bottom,
518 dest.right, dest.top
519 };
520
521 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
522 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
523
524 GLfloat dx = 1.0 / txtWidth;
525 GLfloat dy = 1.0 / txtHeight;
526
527 QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);
528
529 GLfloat textureCoords[] = {
530 srcTextureRect.left, srcTextureRect.top,
531 srcTextureRect.left, srcTextureRect.bottom,
532 srcTextureRect.right, srcTextureRect.bottom,
533 srcTextureRect.right, srcTextureRect.top
534 };
535
536 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
537 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
538
539 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
540
541 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
542 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
543}
544
545
546void QGL2PaintEngineExPrivate::drawOutline(const QVectorPath& path)
547{
548// qDebug("QGL2PaintEngineExPrivate::drawOutline()");
549 if (matrixDirty)
550 updateMatrix();
551
552 pathVertexArray.clear();
553 pathVertexArray.addPath(path, inverseScale);
554
555 if (path.hasImplicitClose()) {
556 // Close the path's outline
557 pathVertexArray.lineToArray(path.points()[0], path.points()[1]);
558 pathVertexArray.stops().last() += 1;
559 }
560
561 prepareForDraw();
562 drawVertexArrays(pathVertexArray, GL_LINE_STRIP);
563}
564
565
566// Assumes everything is configured for the brush you want to use
567void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
568{
569 if (matrixDirty)
570 updateMatrix();
571
572 const QPointF* const points = reinterpret_cast<const QPointF*>(path.points());
573
574
575 // Check to see if there's any hints
576 if (path.shape() == QVectorPath::RectangleHint) {
577 QGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y());
578 prepareForDraw();
579 composite(rect);
580 }
581 else if (path.shape() == QVectorPath::EllipseHint) {
582 pathVertexArray.clear();
583 pathVertexArray.addPath(path, inverseScale);
584 prepareForDraw();
585 drawVertexArrays(pathVertexArray, GL_TRIANGLE_FAN);
586 }
587 else {
588 // The path is too complicated & needs the stencil technique
589 pathVertexArray.clear();
590 pathVertexArray.addPath(path, inverseScale);
591
592 fillStencilWithVertexArray(pathVertexArray, path.hasWindingFill());
593
594 // Stencil the brush onto the dest buffer
595 glStencilFunc(GL_NOTEQUAL, 0, 0xFFFF); // Pass if stencil buff value != 0
596 glEnable(GL_STENCIL_TEST);
597 prepareForDraw();
598 composite(pathVertexArray.boundingRect());
599 glDisable(GL_STENCIL_TEST);
600
601 cleanStencilBuffer(pathVertexArray.boundingRect());
602 }
603}
604
605
606void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill)
607{
608// qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()");
609 if (stencilBuferDirty) {
610 // Clear the stencil buffer to zeros
611 glDisable(GL_STENCIL_TEST);
612 glStencilMask(0xFFFF); // Enable writing to stencil buffer, otherwise glClear wont do anything.
613 glClearStencil(0); // Clear to zero
614 glClear(GL_STENCIL_BUFFER_BIT);
615 stencilBuferDirty = false;
616 }
617
618 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
619 glStencilMask(0xFFFF); // Enable stencil writes
620 glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test
621
622 // Setup the stencil op:
623 if (useWindingFill) {
624 glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP); // Inc. for front-facing triangle
625 glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_DECR_WRAP); //Dec. for back-facing "holes"
626 } else
627 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
628
629 // No point in using a fancy gradiant shader for writing into the stencil buffer!
630 useSimpleShader();
631
632 glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
633 glDisable(GL_BLEND);
634
635 // Draw the vertecies into the stencil buffer:
636 drawVertexArrays(vertexArray, GL_TRIANGLE_FAN);
637
638 // Enable color writes & disable stencil writes
639 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
640 glStencilMask(0);
641}
642
643void QGL2PaintEngineExPrivate::cleanStencilBuffer(const QGLRect& area)
644{
645// qDebug("QGL2PaintEngineExPrivate::cleanStencilBuffer()");
646 useSimpleShader();
647
648 GLfloat rectVerts[] = {
649 area.left, area.top,
650 area.left, area.bottom,
651 area.right, area.bottom,
652 area.right, area.top
653 };
654
655 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
656 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts);
657
658 glEnable(GL_STENCIL_TEST);
659 glStencilFunc(GL_ALWAYS, 0, 0xFFFF); // Always pass the stencil test
660
661 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes
662 glStencilMask(0xFFFF); // Enable writing to stencil buffer
663 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // Write 0's to stencil buffer
664
665 glDisable(GL_BLEND);
666
667 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
668
669 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
670
671 // Enable color writes & disable stencil writes
672 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
673 glStencilMask(0);
674 glDisable(GL_STENCIL_TEST);
675}
676
677void QGL2PaintEngineExPrivate::prepareForDraw()
678{
679 if (brushTextureDirty)
680 updateBrushTexture();
681
682 if (compositionModeDirty)
683 updateCompositionMode();
684
685 if (shaderManager->useCorrectShaderProg()) {
686 // The shader program has changed so mark all uniforms as dirty:
687 brushUniformsDirty = true;
688 brushShaderMatrixUniformDirty = true;
689 }
690
691 if (brushUniformsDirty)
692 updateBrushUniforms();
693
694 if (brushShaderMatrixUniformDirty) {
695 shaderManager->brushShader()->uniforms()[QLatin1String("pmvMatrix")] = pmvMatrix;
696 brushShaderMatrixUniformDirty = false;
697 }
698
699 if ((q->state()->opacity < 0.99f) || !currentBrush->isOpaque())
700 glEnable(GL_BLEND);
701 else
702 glDisable(GL_BLEND);
703}
704
705void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect)
706{
707 // Setup a vertex array for the bounding rect:
708 GLfloat rectVerts[] = {
709 boundingRect.left, boundingRect.top,
710 boundingRect.left, boundingRect.bottom,
711 boundingRect.right, boundingRect.bottom,
712 boundingRect.right, boundingRect.top
713 };
714
715 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
716 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts);
717
718 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
719
720 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
721}
722
723// Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
724void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive)
725{
726 // Now setup the pointer to the vertex array:
727 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
728 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray.data());
729
730 int previousStop = 0;
731 foreach(int stop, vertexArray.stops()) {
732/*
733 qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1);
734 for (int i=previousStop; i<stop; ++i)
735 qDebug(" %02d: [%.2f, %.2f]", i, vertexArray.data()[i].x, vertexArray.data()[i].y);
736*/
737 glDrawArrays(primitive, previousStop, stop - previousStop);
738 previousStop = stop;
739 }
740 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
741}
742
743
744
745
746
747/////////////////////////////////// Public Methods //////////////////////////////////////////
748
749QGL2PaintEngineEx::QGL2PaintEngineEx()
750 : QPaintEngineEx(*(new QGL2PaintEngineExPrivate(this)))
751{
752 qDebug("QGL2PaintEngineEx::QGL2PaintEngineEx()");
753
754}
755
756QGL2PaintEngineEx::~QGL2PaintEngineEx()
757{
758}
759
760void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
761{
762 Q_D(QGL2PaintEngineEx);
763
764 QTime startTime = QTime::currentTime();
765
766 d->setBrush(&brush);
767 d->fill(path);
768 d->setBrush(&(state()->brush)); // reset back to the state's brush
769}
770
771void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
772{
773 Q_D(QGL2PaintEngineEx);
774
775 if (pen.style() == Qt::NoPen)
776 return;
777
778 if ( (pen.isCosmetic() && (pen.style() == Qt::SolidLine)) && (pen.widthF() < 2.5f) )
779 {
780 // We only handle solid, cosmetic pens with a width of 1 pixel
781 const QBrush& brush = pen.brush();
782 d->setBrush(&brush);
783
784 if (pen.widthF() < 0.01f)
785 glLineWidth(1.0);
786 else
787 glLineWidth(pen.widthF());
788
789 d->drawOutline(path);
790 d->setBrush(&(state()->brush));
791 } else
792 return QPaintEngineEx::stroke(path, pen);
793
794}
795
796void QGL2PaintEngineEx::penChanged()
797{
798// qDebug("QGL2PaintEngineEx::penChanged() not implemented!");
799}
800
801
802void QGL2PaintEngineEx::brushChanged()
803{
804// qDebug("QGL2PaintEngineEx::brushChanged()");
805 Q_D(QGL2PaintEngineEx);
806 d->setBrush(&(state()->brush));
807}
808
809void QGL2PaintEngineEx::brushOriginChanged()
810{
811// qDebug("QGL2PaintEngineEx::brushOriginChanged()");
812 Q_D(QGL2PaintEngineEx);
813 d->brushUniformsDirty = true;
814}
815
816void QGL2PaintEngineEx::opacityChanged()
817{
818// qDebug("QGL2PaintEngineEx::opacityChanged()");
819 Q_D(QGL2PaintEngineEx);
820
821 Q_ASSERT(d->shaderManager);
822 d->shaderManager->setUseGlobalOpacity(state()->opacity > 0.999);
823 d->brushUniformsDirty = true;
824}
825
826void QGL2PaintEngineEx::compositionModeChanged()
827{
828// qDebug("QGL2PaintEngineEx::compositionModeChanged()");
829 Q_D(QGL2PaintEngineEx);
830 d->compositionModeDirty = true;
831}
832
833void QGL2PaintEngineEx::renderHintsChanged()
834{
835// qDebug("QGL2PaintEngineEx::renderHintsChanged() not implemented!");
836}
837
838void QGL2PaintEngineEx::transformChanged()
839{
840 Q_D(QGL2PaintEngineEx);
841 d->matrixDirty = true;
842}
843
844
845void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, const QRectF & src)
846{
847 Q_D(QGL2PaintEngineEx);
848 glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
849
850 d->ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true);
851
852 //FIXME: we should use hasAlpha() instead, but that's SLOW at the moment
853 if ((state()->opacity < 0.99f) || pixmap.hasAlphaChannel())
854 glEnable(GL_BLEND);
855 else
856 glDisable(GL_BLEND);
857
858 d->drawTexture(dest, src, pixmap.width(), pixmap.height());
859}
860
861void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src,
862 Qt::ImageConversionFlags)
863{
864 Q_D(QGL2PaintEngineEx);
865 glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
866 d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
867
868 if ((state()->opacity < 0.99f) || image.hasAlphaChannel())
869 glEnable(GL_BLEND);
870 else
871 glDisable(GL_BLEND);
872
873 d->drawTexture(dest, src, image.width(), image.height());
874}
875
876void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
877{
878 QOpenGLPaintEngineState *s = state();
879
880 const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
881
882 bool drawCached = true;
883
884 if (state()->pen.brush().style() != Qt::SolidPattern)
885 drawCached = false;
886
887 if (s->matrix.type() > QTransform::TxTranslate)
888 drawCached = false;
889
890 // don't try to cache huge fonts
891 if (ti.fontEngine->fontDef.pixelSize * qSqrt(s->matrix.determinant()) >= 64)
892 drawCached = false;
893
894 if (drawCached) {
895 drawCachedGlyphs(p, ti);
896 return;
897 }
898
899 QPaintEngineEx::drawTextItem(p, ti);
900}
901
902void QGL2PaintEngineEx::drawCachedGlyphs(const QPointF &p, const QTextItemInt &ti)
903{
904 Q_D(QGL2PaintEngineEx);
905 QOpenGLPaintEngineState *s = state();
906
907 QVarLengthArray<QFixedPoint> positions;
908 QVarLengthArray<glyph_t> glyphs;
909 QTransform matrix;
910 matrix.translate(p.x(), p.y());
911 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
912
913 QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0
914 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
915 : QFontEngineGlyphCache::Raster_A8;
916
917 QImageTextureGlyphCache *cache =
918 (QImageTextureGlyphCache *) ti.fontEngine->glyphCache(glyphType, s->matrix);
919 if (!cache) {
920 cache = new QImageTextureGlyphCache(glyphType, s->matrix);
921 ti.fontEngine->setGlyphCache(glyphType, cache);
922 }
923
924 cache->populate(ti, glyphs, positions);
925
926 const QImage &image = cache->image();
927 int margin = cache->glyphMargin();
928
929 glActiveTexture(QT_BRUSH_TEXTURE_UNIT);
930 d->ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
931
932 glEnable(GL_BLEND);
933
934 d->shaderManager->textShader()->use();
935 d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
936
937 if (d->compositionModeDirty)
938 d->updateCompositionMode();
939
940 if (d->matrixDirty)
941 d->updateMatrix();
942
943 if (d->textShaderMatrixUniformDirty) {
944 d->shaderManager->textShader()->uniforms()[QLatin1String("pmvMatrix")] = d->pmvMatrix;
945 d->textShaderMatrixUniformDirty = false;
946 }
947
948 d->shaderManager->textShader()->uniforms()[QLatin1String("textureSampler")] = QT_BRUSH_TEXTURE_UNIT;
949 QColor col = d->premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity);
950 d->shaderManager->textShader()->uniforms()[QLatin1String("fragmentColor")] = col;
951
952 GLfloat dx = 1.0 / image.width();
953 GLfloat dy = 1.0 / image.height();
954
955 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
956 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
957 for (int i=0; i<glyphs.size(); ++i) {
958 const QTextureGlyphCache::Coord &c = cache->coords.value(glyphs[i]);
959 int x = positions[i].x.toInt() + c.baseLineX - margin;
960 int y = positions[i].y.toInt() - c.baseLineY - margin;
961
962 QGLRect dest = QRectF(x, y, c.w, c.h);
963 QGLRect src = QRectF(c.x, c.y, c.w, c.h);
964
965 GLfloat vertexCoords[] = {
966 dest.left, dest.top,
967 dest.left, dest.bottom,
968 dest.right, dest.bottom,
969 dest.right, dest.top
970 };
971
972 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);
973
974 QGLRect srcTextureRect(src.left*dx, 1.0 - src.top*dy, src.right*dx, 1.0 - src.bottom*dy);
975
976 GLfloat textureCoords[] = {
977 srcTextureRect.left, srcTextureRect.top,
978 srcTextureRect.left, srcTextureRect.bottom,
979 srcTextureRect.right, srcTextureRect.bottom,
980 srcTextureRect.right, srcTextureRect.top
981 };
982
983 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
984
985 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
986 }
987 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
988 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
989}
990
991bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
992{
993 Q_D(QGL2PaintEngineEx);
994
995// qDebug("QGL2PaintEngineEx::begin()");
996
997 QGLWidget* widget = static_cast<QGLWidget*>(pdev);
998 d->ctx = const_cast<QGLContext*>(widget->context());
999 d->ctx->makeCurrent();
1000 d->width = widget->width();
1001 d->height = widget->height();
1002
1003 if (!d->shaderManager)
1004 d->shaderManager = new QGLPEXShaderManager(d->ctx);
1005
1006 glViewport(0, 0, d->width, d->height);
1007
1008// glClearColor(0.0, 1.0, 0.0, 1.0);
1009// glClear(GL_COLOR_BUFFER_BIT);
1010// d->ctx->swapBuffers();
1011// qDebug("You should see green now");
1012// sleep(5);
1013
1014 d->brushTextureDirty = true;
1015 d->brushUniformsDirty = true;
1016 d->matrixDirty = true;
1017 d->compositionModeDirty = true;
1018 d->stencilBuferDirty = true;
1019
1020 d->use_system_clip = !systemClip().isEmpty();
1021
1022 glDisable(GL_DEPTH_TEST);
1023
1024 return true;
1025}
1026
1027bool QGL2PaintEngineEx::end()
1028{
1029 Q_D(QGL2PaintEngineEx);
1030 d->ctx->swapBuffers();
1031 return false;
1032}
1033
1034
1035/////////////////////////////////// State/Clipping stolen from QOpenGLPaintEngine //////////////////////////////////////////
1036
1037void QGL2PaintEngineEx::clipEnabledChanged()
1038{
1039 Q_D(QGL2PaintEngineEx);
1040
1041 d->updateDepthClip();
1042}
1043
1044void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
1045{
1046// qDebug("QGL2PaintEngineEx::clip()");
1047 const qreal *points = path.points();
1048 const QPainterPath::ElementType *types = path.elements();
1049 if (!types && path.shape() == QVectorPath::RectangleHint) {
1050 QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
1051 updateClipRegion(QRegion(r.toRect()), op);
1052 return;
1053 }
1054
1055 QPainterPath p;
1056 if (types) {
1057 int id = 0;
1058 for (int i=0; i<path.elementCount(); ++i) {
1059 switch(types[i]) {
1060 case QPainterPath::MoveToElement:
1061 p.moveTo(QPointF(points[id], points[id+1]));
1062 id+=2;
1063 break;
1064 case QPainterPath::LineToElement:
1065 p.lineTo(QPointF(points[id], points[id+1]));
1066 id+=2;
1067 break;
1068 case QPainterPath::CurveToElement: {
1069 QPointF p1(points[id], points[id+1]);
1070 QPointF p2(points[id+2], points[id+3]);
1071 QPointF p3(points[id+4], points[id+5]);
1072 p.cubicTo(p1, p2, p3);
1073 id+=6;
1074 break;
1075 }
1076 case QPainterPath::CurveToDataElement:
1077 ;
1078 break;
1079 }
1080 }
1081 } else if (!path.isEmpty()) {
1082 p.moveTo(QPointF(points[0], points[1]));
1083 int id = 2;
1084 for (int i=1; i<path.elementCount(); ++i) {
1085 p.lineTo(QPointF(points[id], points[id+1]));
1086 id+=2;
1087 }
1088 }
1089 if (path.hints() & QVectorPath::WindingFill)
1090 p.setFillRule(Qt::WindingFill);
1091
1092 updateClipRegion(QRegion(p.toFillPolygon().toPolygon(), p.fillRule()), op);
1093 return;
1094}
1095
1096void QGL2PaintEngineEx::updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op)
1097{
1098// qDebug("QGL2PaintEngineEx::updateClipRegion()");
1099 Q_D(QGL2PaintEngineEx);
1100
1101 QRegion sysClip = systemClip();
1102 if (op == Qt::NoClip && !d->use_system_clip) {
1103 state()->hasClipping = false;
1104 state()->clipRegion = QRegion();
1105 d->updateDepthClip();
1106 return;
1107 }
1108
1109 bool isScreenClip = false;
1110 if (!d->use_system_clip) {
1111 QVector<QRect> untransformedRects = clipRegion.rects();
1112
1113 if (untransformedRects.size() == 1) {
1114 QPainterPath path;
1115 path.addRect(untransformedRects[0]);
1116 //path = d->matrix.map(path);
1117 path = state()->matrix.map(path);
1118
1119// if (path.contains(QRectF(QPointF(), d->drawable.size())))
1120// isScreenClip = true;
1121 if (path.contains(QRectF(0.0, 0.0, d->width, d->height)))
1122 isScreenClip = true;
1123 }
1124 }
1125
1126// QRegion region = isScreenClip ? QRegion() : clipRegion * d->matrix;
1127 QRegion region = isScreenClip ? QRegion() : clipRegion * state()->matrix;
1128 switch (op) {
1129 case Qt::NoClip:
1130 if (!d->use_system_clip)
1131 break;
1132 state()->clipRegion = sysClip;
1133 break;
1134 case Qt::IntersectClip:
1135 if (isScreenClip)
1136 return;
1137 if (state()->hasClipping) {
1138 state()->clipRegion &= region;
1139 break;
1140 }
1141 // fall through
1142 case Qt::ReplaceClip:
1143 if (d->use_system_clip && !sysClip.isEmpty())
1144 state()->clipRegion = region & sysClip;
1145 else
1146 state()->clipRegion = region;
1147 break;
1148 case Qt::UniteClip:
1149 state()->clipRegion |= region;
1150 if (d->use_system_clip && !sysClip.isEmpty())
1151 state()->clipRegion &= sysClip;
1152 break;
1153 default:
1154 break;
1155 }
1156
1157 if (isScreenClip) {
1158 state()->hasClipping = false;
1159 state()->clipRegion = QRegion();
1160 } else {
1161 state()->hasClipping = op != Qt::NoClip || d->use_system_clip;
1162 }
1163
1164 if (state()->hasClipping && state()->clipRegion.rects().size() == 1)
1165 state()->fastClip = state()->clipRegion.rects().at(0);
1166 else
1167 state()->fastClip = QRect();
1168
1169 d->updateDepthClip();
1170}
1171
1172
1173void QGL2PaintEngineExPrivate::updateDepthClip()
1174{
1175// qDebug("QGL2PaintEngineExPrivate::updateDepthClip()");
1176
1177 Q_Q(QGL2PaintEngineEx);
1178
1179 glDisable(GL_DEPTH_TEST);
1180 glDisable(GL_SCISSOR_TEST);
1181
1182 if (!q->state()->hasClipping)
1183 return;
1184
1185 QRect fastClip;
1186 if (q->state()->clipEnabled) {
1187 fastClip = q->state()->fastClip;
1188 } else if (use_system_clip && q->systemClip().rects().count() == 1) {
1189 fastClip = q->systemClip().rects().at(0);
1190 }
1191
1192 if (!fastClip.isEmpty()) {
1193 glEnable(GL_SCISSOR_TEST);
1194
1195 const int left = fastClip.left();
1196 const int width = fastClip.width();
1197 const int bottom = height - (fastClip.bottom() + 1);
1198 const int height = fastClip.height();
1199
1200 glScissor(left, bottom, width, height);
1201 return;
1202 }
1203
1204 glClearDepthf(0x0);
1205 glDepthMask(true);
1206 glClear(GL_DEPTH_BUFFER_BIT);
1207 glClearDepthf(0x1);
1208
1209 const QVector<QRect> rects = q->state()->clipEnabled ? q->state()->clipRegion.rects() : q->systemClip().rects();
1210 glEnable(GL_SCISSOR_TEST);
1211 for (int i = 0; i < rects.size(); ++i) {
1212 QRect rect = rects.at(i);
1213
1214 const int left = rect.left();
1215 const int width = rect.width();
1216 const int bottom = height - (rect.bottom() + 1);
1217 const int height = rect.height();
1218
1219 glScissor(left, bottom, width, height);
1220
1221 glClear(GL_DEPTH_BUFFER_BIT);
1222 }
1223 glDisable(GL_SCISSOR_TEST);
1224
1225 glDepthMask(false);
1226 glDepthFunc(GL_LEQUAL);
1227 glEnable(GL_DEPTH_TEST);
1228}
1229
1230
1231
1232void QGL2PaintEngineEx::setState(QPainterState *s)
1233{
1234// qDebug("QGL2PaintEngineEx::setState()");
1235
1236 Q_D(QGL2PaintEngineEx);
1237 QPaintEngineEx::setState(s);
1238
1239 d->updateDepthClip();
1240
1241 d->matrixDirty = true;
1242 d->compositionModeDirty = true;
1243 d->brushTextureDirty = true;
1244 d->brushUniformsDirty = true;
1245 d->simpleShaderMatrixUniformDirty = true;
1246 d->brushShaderMatrixUniformDirty = true;
1247 d->imageShaderMatrixUniformDirty = true;
1248 d->textShaderMatrixUniformDirty = true;
1249}
1250
1251QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const
1252{
1253 QOpenGLPaintEngineState *s;
1254 if (!orig)
1255 s = new QOpenGLPaintEngineState();
1256 else
1257 s = new QOpenGLPaintEngineState(*static_cast<QOpenGLPaintEngineState *>(orig));
1258
1259 return s;
1260}
1261
1262QOpenGLPaintEngineState::QOpenGLPaintEngineState(QOpenGLPaintEngineState &other)
1263 : QPainterState(other)
1264{
1265 clipRegion = other.clipRegion;
1266 hasClipping = other.hasClipping;
1267 fastClip = other.fastClip;
1268}
1269
1270QOpenGLPaintEngineState::QOpenGLPaintEngineState()
1271{
1272 hasClipping = false;
1273}
1274
1275QOpenGLPaintEngineState::~QOpenGLPaintEngineState()
1276{
1277}
1278
Note: See TracBrowser for help on using the repository browser.