73 #include <private/qmath_p.h> |
73 #include <private/qmath_p.h> |
74 #include <private/qpaintengineex_p.h> |
74 #include <private/qpaintengineex_p.h> |
75 #include <QPaintEngine> |
75 #include <QPaintEngine> |
76 #include <private/qpainter_p.h> |
76 #include <private/qpainter_p.h> |
77 #include <private/qfontengine_p.h> |
77 #include <private/qfontengine_p.h> |
78 #include <private/qtextureglyphcache_p.h> |
|
79 #include <private/qpixmapdata_gl_p.h> |
78 #include <private/qpixmapdata_gl_p.h> |
80 #include <private/qdatabuffer_p.h> |
79 #include <private/qdatabuffer_p.h> |
81 |
80 |
82 #include "qglgradientcache_p.h" |
81 #include "qglgradientcache_p.h" |
83 #include "qglengineshadermanager_p.h" |
82 #include "qglengineshadermanager_p.h" |
84 #include "qgl2pexvertexarray_p.h" |
83 #include "qgl2pexvertexarray_p.h" |
85 |
|
86 #include "qtriangulatingstroker_p.h" |
84 #include "qtriangulatingstroker_p.h" |
|
85 #include "qtextureglyphcache_gl_p.h" |
87 |
86 |
88 #include <QDebug> |
87 #include <QDebug> |
89 |
88 |
90 QT_BEGIN_NAMESPACE |
89 QT_BEGIN_NAMESPACE |
91 |
90 |
92 //#define QT_GL_NO_SCISSOR_TEST |
91 //#define QT_GL_NO_SCISSOR_TEST |
93 |
92 #if defined(Q_WS_WIN) |
94 static const GLuint GL_STENCIL_HIGH_BIT = 0x80; |
|
95 static const GLuint QT_BRUSH_TEXTURE_UNIT = 0; |
|
96 static const GLuint QT_IMAGE_TEXTURE_UNIT = 0; //Can be the same as brush texture unit |
|
97 static const GLuint QT_MASK_TEXTURE_UNIT = 1; |
|
98 static const GLuint QT_BACKGROUND_TEXTURE_UNIT = 2; |
|
99 |
|
100 #ifdef Q_WS_WIN |
|
101 extern Q_GUI_EXPORT bool qt_cleartype_enabled; |
93 extern Q_GUI_EXPORT bool qt_cleartype_enabled; |
102 #endif |
94 #endif |
103 |
|
104 class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache |
|
105 { |
|
106 Q_OBJECT |
|
107 public: |
|
108 QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix); |
|
109 ~QGLTextureGlyphCache(); |
|
110 |
|
111 virtual void createTextureData(int width, int height); |
|
112 virtual void resizeTextureData(int width, int height); |
|
113 virtual void fillTexture(const Coord &c, glyph_t glyph); |
|
114 virtual int glyphMargin() const; |
|
115 |
|
116 inline GLuint texture() const { return m_texture; } |
|
117 |
|
118 inline int width() const { return m_width; } |
|
119 inline int height() const { return m_height; } |
|
120 |
|
121 inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; } |
|
122 |
|
123 |
|
124 public Q_SLOTS: |
|
125 void contextDestroyed(const QGLContext *context) { |
|
126 if (context == ctx) { |
|
127 QList<const QGLContext *> shares = qgl_share_reg()->shares(ctx); |
|
128 if (shares.isEmpty()) { |
|
129 glDeleteFramebuffers(1, &m_fbo); |
|
130 if (m_width || m_height) |
|
131 glDeleteTextures(1, &m_texture); |
|
132 ctx = 0; |
|
133 } else { |
|
134 // since the context holding the texture is shared, and |
|
135 // about to be destroyed, we have to transfer ownership |
|
136 // of the texture to one of the share contexts |
|
137 ctx = const_cast<QGLContext *>((ctx == shares.at(0)) ? shares.at(1) : shares.at(0)); |
|
138 } |
|
139 } |
|
140 } |
|
141 |
|
142 private: |
|
143 QGLContext *ctx; |
|
144 |
|
145 QGL2PaintEngineExPrivate *pex; |
|
146 |
|
147 GLuint m_texture; |
|
148 GLuint m_fbo; |
|
149 |
|
150 int m_width; |
|
151 int m_height; |
|
152 |
|
153 QGLShaderProgram *m_program; |
|
154 }; |
|
155 |
|
156 QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix) |
|
157 : QTextureGlyphCache(type, matrix) |
|
158 , ctx(context) |
|
159 , m_width(0) |
|
160 , m_height(0) |
|
161 { |
|
162 glGenFramebuffers(1, &m_fbo); |
|
163 connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)), |
|
164 SLOT(contextDestroyed(const QGLContext*))); |
|
165 } |
|
166 |
|
167 QGLTextureGlyphCache::~QGLTextureGlyphCache() |
|
168 { |
|
169 if (ctx) { |
|
170 QGLShareContextScope scope(ctx); |
|
171 glDeleteFramebuffers(1, &m_fbo); |
|
172 |
|
173 if (m_width || m_height) |
|
174 glDeleteTextures(1, &m_texture); |
|
175 } |
|
176 } |
|
177 |
|
178 void QGLTextureGlyphCache::createTextureData(int width, int height) |
|
179 { |
|
180 glGenTextures(1, &m_texture); |
|
181 glBindTexture(GL_TEXTURE_2D, m_texture); |
|
182 |
|
183 m_width = width; |
|
184 m_height = height; |
|
185 |
|
186 QVarLengthArray<uchar> data(width * height); |
|
187 for (int i = 0; i < data.size(); ++i) |
|
188 data[i] = 0; |
|
189 |
|
190 if (m_type == QFontEngineGlyphCache::Raster_RGBMask) |
|
191 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]); |
|
192 else |
|
193 glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]); |
|
194 |
|
195 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
196 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|
197 } |
|
198 |
|
199 void QGLTextureGlyphCache::resizeTextureData(int width, int height) |
|
200 { |
|
201 // ### the QTextureGlyphCache API needs to be reworked to allow |
|
202 // ### resizeTextureData to fail |
|
203 |
|
204 int oldWidth = m_width; |
|
205 int oldHeight = m_height; |
|
206 |
|
207 GLuint oldTexture = m_texture; |
|
208 createTextureData(width, height); |
|
209 |
|
210 glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo); |
|
211 |
|
212 GLuint tmp_texture; |
|
213 glGenTextures(1, &tmp_texture); |
|
214 glBindTexture(GL_TEXTURE_2D, tmp_texture); |
|
215 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0, |
|
216 GL_RGBA, GL_UNSIGNED_BYTE, NULL); |
|
217 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|
218 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|
219 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
|
220 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
|
221 glBindTexture(GL_TEXTURE_2D, 0); |
|
222 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, |
|
223 GL_TEXTURE_2D, tmp_texture, 0); |
|
224 |
|
225 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); |
|
226 glBindTexture(GL_TEXTURE_2D, oldTexture); |
|
227 |
|
228 pex->transferMode(BrushDrawingMode); |
|
229 |
|
230 #ifndef QT_OPENGL_ES_2 |
|
231 if (pex->inRenderText) |
|
232 glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_SCISSOR_BIT); |
|
233 #endif |
|
234 |
|
235 glDisable(GL_STENCIL_TEST); |
|
236 glDisable(GL_DEPTH_TEST); |
|
237 glDisable(GL_SCISSOR_TEST); |
|
238 glDisable(GL_BLEND); |
|
239 |
|
240 glViewport(0, 0, oldWidth, oldHeight); |
|
241 |
|
242 float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 }; |
|
243 float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 }; |
|
244 |
|
245 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
|
246 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
|
247 |
|
248 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray); |
|
249 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray); |
|
250 |
|
251 pex->shaderManager->blitProgram()->bind(); |
|
252 pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); |
|
253 pex->shaderManager->setDirty(); |
|
254 |
|
255 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); |
|
256 |
|
257 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
|
258 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
|
259 |
|
260 glBindTexture(GL_TEXTURE_2D, m_texture); |
|
261 |
|
262 #ifdef QT_OPENGL_ES_2 |
|
263 QDataBuffer<uchar> buffer(4*oldWidth*oldHeight); |
|
264 buffer.resize(4*oldWidth*oldHeight); |
|
265 glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data()); |
|
266 |
|
267 // do an in-place conversion from GL_RGBA to GL_ALPHA |
|
268 for (int i=0; i<oldWidth*oldHeight; ++i) |
|
269 buffer.data()[i] = buffer.at(4*i + 3); |
|
270 |
|
271 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, |
|
272 GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data()); |
|
273 #else |
|
274 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); |
|
275 #endif |
|
276 |
|
277 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, |
|
278 GL_RENDERBUFFER_EXT, 0); |
|
279 glDeleteTextures(1, &tmp_texture); |
|
280 glDeleteTextures(1, &oldTexture); |
|
281 |
|
282 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); |
|
283 |
|
284 glViewport(0, 0, pex->width, pex->height); |
|
285 pex->updateClipScissorTest(); |
|
286 |
|
287 #ifndef QT_OPENGL_ES_2 |
|
288 if (pex->inRenderText) |
|
289 glPopAttrib(); |
|
290 #endif |
|
291 } |
|
292 |
|
293 void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph) |
|
294 { |
|
295 QImage mask = textureMapForGlyph(glyph); |
|
296 const int maskWidth = mask.width(); |
|
297 const int maskHeight = mask.height(); |
|
298 |
|
299 if (mask.format() == QImage::Format_Mono) { |
|
300 mask = mask.convertToFormat(QImage::Format_Indexed8); |
|
301 for (int y = 0; y < maskHeight; ++y) { |
|
302 uchar *src = (uchar *) mask.scanLine(y); |
|
303 for (int x = 0; x < maskWidth; ++x) |
|
304 src[x] = -src[x]; // convert 0 and 1 into 0 and 255 |
|
305 } |
|
306 } |
|
307 |
|
308 |
|
309 glBindTexture(GL_TEXTURE_2D, m_texture); |
|
310 if (mask.format() == QImage::Format_RGB32) { |
|
311 glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits()); |
|
312 } else { |
|
313 #ifdef QT_OPENGL_ES2 |
|
314 glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits()); |
|
315 #else |
|
316 // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is |
|
317 // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista |
|
318 // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a |
|
319 // multiple of four bytes per line, and most of the glyph shows up correctly in the |
|
320 // texture, which makes me think that this is a driver bug. |
|
321 // One workaround is to make sure the mask width is a multiple of four bytes, for instance |
|
322 // by converting it to a format with four bytes per pixel. Another is to copy one line at a |
|
323 // time. |
|
324 |
|
325 for (int i = 0; i < maskHeight; ++i) |
|
326 glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i)); |
|
327 #endif |
|
328 } |
|
329 } |
|
330 |
|
331 int QGLTextureGlyphCache::glyphMargin() const |
|
332 { |
|
333 #if defined(Q_WS_MAC) |
|
334 return 2; |
|
335 #elif defined (Q_WS_X11) |
|
336 return 0; |
|
337 #else |
|
338 return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; |
|
339 #endif |
|
340 } |
|
341 |
95 |
342 extern QImage qt_imageForBrush(int brushStyle, bool invert); |
96 extern QImage qt_imageForBrush(int brushStyle, bool invert); |
343 |
97 |
344 ////////////////////////////////// Private Methods ////////////////////////////////////////// |
98 ////////////////////////////////// Private Methods ////////////////////////////////////////// |
345 |
99 |
581 // This assumes the shader manager has already setup the correct shader program |
332 // This assumes the shader manager has already setup the correct shader program |
582 void QGL2PaintEngineExPrivate::updateMatrix() |
333 void QGL2PaintEngineExPrivate::updateMatrix() |
583 { |
334 { |
584 // qDebug("QGL2PaintEngineExPrivate::updateMatrix()"); |
335 // qDebug("QGL2PaintEngineExPrivate::updateMatrix()"); |
585 |
336 |
586 // We set up the 4x4 transformation matrix on the vertex shaders to |
337 const QTransform& transform = q->state()->matrix; |
587 // be the equivalent of glOrtho(0, w, h, 0, -1, 1) * transform: |
338 |
|
339 // The projection matrix converts from Qt's coordinate system to GL's coordinate system |
|
340 // * GL's viewport is 2x2, Qt's is width x height |
|
341 // * GL has +y -> -y going from bottom -> top, Qt is the other way round |
|
342 // * GL has [0,0] in the center, Qt has it in the top-left |
588 // |
343 // |
589 // | 2/width 0 0 -1 | | m11 m21 0 dx | |
344 // This results in the Projection matrix below, which is multiplied by the painter's |
590 // | 0 -2/height 0 1 | | m12 m22 0 dy | |
345 // transformation matrix, as shown below: |
591 // | 0 0 -1 0 | * | 0 0 1 0 | |
|
592 // | 0 0 0 1 | | m13 m23 0 m33 | |
|
593 // |
346 // |
594 // We expand out the multiplication to save the cost of a full 4x4 |
347 // Projection Matrix Painter Transform |
595 // matrix multiplication as most of the components are trivial. |
348 // ------------------------------------------------ ------------------------ |
596 const QTransform& transform = q->state()->matrix; |
349 // | 2.0 / width | 0.0 | -1.0 | | m11 | m21 | dx | |
597 |
350 // | 0.0 | -2.0 / height | 1.0 | * | m12 | m22 | dy | |
598 qreal wfactor = 2.0 / width; |
351 // | 0.0 | 0.0 | 1.0 | | m13 | m23 | m33 | |
599 qreal hfactor = -2.0 / height; |
352 // ------------------------------------------------ ------------------------ |
600 |
353 // |
601 pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13(); |
354 // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies |
602 pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13(); |
355 |
603 pmvMatrix[0][2] = 0.0; |
356 const GLfloat wfactor = 2.0f / width; |
604 pmvMatrix[0][3] = transform.m13(); |
357 const GLfloat hfactor = -2.0f / height; |
605 pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23(); |
358 GLfloat dx = transform.dx(); |
606 pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23(); |
359 GLfloat dy = transform.dy(); |
607 pmvMatrix[1][2] = 0.0; |
360 |
608 pmvMatrix[1][3] = transform.m23(); |
361 // Non-integer translates can have strange effects for some rendering operations such as |
609 pmvMatrix[2][0] = 0.0; |
362 // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid. |
610 pmvMatrix[2][1] = 0.0; |
363 if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) { |
611 pmvMatrix[2][2] = -1.0; |
364 // 0.50 needs to rounded down to 0.0 for consistency with raster engine: |
612 pmvMatrix[2][3] = 0.0; |
365 dx = ceilf(dx - 0.5f); |
613 pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33(); |
366 dy = ceilf(dy - 0.5f); |
614 pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33(); |
367 } |
615 pmvMatrix[3][2] = 0.0; |
368 |
616 pmvMatrix[3][3] = transform.m33(); |
369 if (addOffset) { |
|
370 dx += 0.49f; |
|
371 dy += 0.49f; |
|
372 } |
|
373 |
|
374 pmvMatrix[0][0] = (wfactor * transform.m11()) - transform.m13(); |
|
375 pmvMatrix[1][0] = (wfactor * transform.m21()) - transform.m23(); |
|
376 pmvMatrix[2][0] = (wfactor * dx) - transform.m33(); |
|
377 pmvMatrix[0][1] = (hfactor * transform.m12()) + transform.m13(); |
|
378 pmvMatrix[1][1] = (hfactor * transform.m22()) + transform.m23(); |
|
379 pmvMatrix[2][1] = (hfactor * dy) + transform.m33(); |
|
380 pmvMatrix[0][2] = transform.m13(); |
|
381 pmvMatrix[1][2] = transform.m23(); |
|
382 pmvMatrix[2][2] = transform.m33(); |
617 |
383 |
618 // 1/10000 == 0.0001, so we have good enough res to cover curves |
384 // 1/10000 == 0.0001, so we have good enough res to cover curves |
619 // that span the entire widget... |
385 // that span the entire widget... |
620 inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), |
386 inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), |
621 qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), |
387 qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), |
622 qreal(0.0001)); |
388 qreal(0.0001)); |
623 |
389 |
624 matrixDirty = false; |
390 matrixDirty = false; |
625 |
391 |
626 // The actual data has been updated so both shader program's uniforms need updating |
392 // Set the PMV matrix attribute. As we use an attributes rather than uniforms, we only |
627 simpleShaderMatrixUniformDirty = true; |
393 // need to do this once for every matrix change and persists across all shader programs. |
628 shaderMatrixUniformDirty = true; |
394 glVertexAttrib3fv(QT_PMV_MATRIX_1_ATTR, pmvMatrix[0]); |
|
395 glVertexAttrib3fv(QT_PMV_MATRIX_2_ATTR, pmvMatrix[1]); |
|
396 glVertexAttrib3fv(QT_PMV_MATRIX_3_ATTR, pmvMatrix[2]); |
629 |
397 |
630 dasher.setInvScale(inverseScale); |
398 dasher.setInvScale(inverseScale); |
631 stroker.setInvScale(inverseScale); |
399 stroker.setInvScale(inverseScale); |
632 } |
400 } |
633 |
401 |
772 glDisable(GL_DEPTH_TEST); |
556 glDisable(GL_DEPTH_TEST); |
773 glDisable(GL_SCISSOR_TEST); |
557 glDisable(GL_SCISSOR_TEST); |
774 glDepthMask(true); |
558 glDepthMask(true); |
775 glDepthFunc(GL_LESS); |
559 glDepthFunc(GL_LESS); |
776 glClearDepth(1); |
560 glClearDepth(1); |
|
561 glStencilMask(0xff); |
|
562 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
|
563 glStencilFunc(GL_ALWAYS, 0, 0xff); |
|
564 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
|
565 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
|
566 glDisableVertexAttribArray(QT_OPACITY_ATTR); |
|
567 #ifndef QT_OPENGL_ES_2 |
|
568 glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // color may have been changed by glVertexAttrib() |
|
569 #endif |
777 } |
570 } |
778 |
571 |
779 void QGL2PaintEngineEx::endNativePainting() |
572 void QGL2PaintEngineEx::endNativePainting() |
780 { |
573 { |
781 Q_D(QGL2PaintEngineEx); |
574 Q_D(QGL2PaintEngineEx); |
782 d->needsSync = true; |
575 d->needsSync = true; |
783 } |
576 } |
784 |
577 |
785 const QGLContext *QGL2PaintEngineEx::context() |
|
786 { |
|
787 Q_D(QGL2PaintEngineEx); |
|
788 return d->ctx; |
|
789 } |
|
790 |
|
791 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) |
578 void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) |
792 { |
579 { |
793 if (newMode == mode) |
580 if (newMode == mode) |
794 return; |
581 return; |
795 |
582 |
796 if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) { |
583 if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) { |
797 glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
584 lastTextureUsed = GLuint(-1); |
798 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
|
799 glDisableVertexAttribArray(QT_OPACITY_ATTR); |
|
800 |
|
801 lastTexture = GLuint(-1); |
|
802 } |
585 } |
803 |
586 |
804 if (newMode == TextDrawingMode) { |
587 if (newMode == TextDrawingMode) { |
805 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
588 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); |
806 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
589 setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); |
807 |
|
808 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); |
|
809 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); |
|
810 } |
590 } |
811 |
591 |
812 if (newMode == ImageDrawingMode) { |
592 if (newMode == ImageDrawingMode) { |
813 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
593 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray); |
814 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
594 setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray); |
815 |
|
816 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticVertexCoordinateArray); |
|
817 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray); |
|
818 } |
595 } |
819 |
596 |
820 if (newMode == ImageArrayDrawingMode) { |
597 if (newMode == ImageArrayDrawingMode) { |
821 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
598 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data()); |
822 glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR); |
599 setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data()); |
823 glEnableVertexAttribArray(QT_OPACITY_ATTR); |
600 setVertexAttributePointer(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data()); |
824 |
|
825 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data()); |
|
826 glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data()); |
|
827 glVertexAttribPointer(QT_OPACITY_ATTR, 1, GL_FLOAT, GL_FALSE, 0, opacityArray.data()); |
|
828 } |
601 } |
829 |
602 |
830 // This needs to change when we implement high-quality anti-aliasing... |
603 // This needs to change when we implement high-quality anti-aliasing... |
831 if (newMode != TextDrawingMode) |
604 if (newMode != TextDrawingMode) |
832 shaderManager->setMaskType(QGLEngineShaderManager::NoMask); |
605 shaderManager->setMaskType(QGLEngineShaderManager::NoMask); |
1060 } else { // TriStripStrokeFillMode |
832 } else { // TriStripStrokeFillMode |
1061 Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops |
833 Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops |
1062 glStencilMask(GL_STENCIL_HIGH_BIT); |
834 glStencilMask(GL_STENCIL_HIGH_BIT); |
1063 #if 0 |
835 #if 0 |
1064 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit |
836 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit |
1065 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
837 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data); |
1066 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); |
|
1067 glDrawArrays(GL_TRIANGLE_STRIP, 0, count); |
838 glDrawArrays(GL_TRIANGLE_STRIP, 0, count); |
1068 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
|
1069 #else |
839 #else |
1070 |
840 |
1071 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); |
841 glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); |
1072 if (q->state()->clipTestEnabled) { |
842 if (q->state()->clipTestEnabled) { |
1073 glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT, |
843 glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT, |
1074 ~GL_STENCIL_HIGH_BIT); |
844 ~GL_STENCIL_HIGH_BIT); |
1075 } else { |
845 } else { |
1076 glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff); |
846 glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff); |
1077 } |
847 } |
1078 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
848 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data); |
1079 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); |
|
1080 glDrawArrays(GL_TRIANGLE_STRIP, 0, count); |
849 glDrawArrays(GL_TRIANGLE_STRIP, 0, count); |
1081 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
|
1082 #endif |
850 #endif |
1083 } |
851 } |
1084 |
852 |
1085 // Enable color writes & disable stencil writes |
853 // Enable color writes & disable stencil writes |
1086 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
854 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
1087 |
|
1088 #ifndef QT_OPENGL_ES_2 |
|
1089 if (inRenderText) |
|
1090 glPopAttrib(); |
|
1091 #endif |
|
1092 |
|
1093 } |
855 } |
1094 |
856 |
1095 /* |
857 /* |
1096 If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1, |
858 If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1, |
1097 restore the stencil buffer to a pristine state. The current clip region |
859 restore the stencil buffer to a pristine state. The current clip region |
1272 |
991 |
1273 void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush) |
992 void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush) |
1274 { |
993 { |
1275 Q_D(QGL2PaintEngineEx); |
994 Q_D(QGL2PaintEngineEx); |
1276 |
995 |
1277 Qt::BrushStyle style = qbrush_style(brush); |
996 if (qbrush_style(brush) == Qt::NoBrush) |
1278 if (style == Qt::NoBrush) |
|
1279 return; |
997 return; |
1280 if (!d->inRenderText) |
998 ensureActive(); |
1281 ensureActive(); |
|
1282 |
|
1283 QOpenGL2PaintEngineState *s = state(); |
|
1284 bool doOffset = !(s->renderHints & QPainter::Antialiasing) && |
|
1285 (style == Qt::SolidPattern) && |
|
1286 !d->multisamplingAlwaysEnabled; |
|
1287 |
|
1288 if (doOffset) { |
|
1289 d->temporaryTransform = s->matrix; |
|
1290 QTransform tx = QTransform::fromTranslate(.49, .49); |
|
1291 s->matrix = s->matrix * tx; |
|
1292 d->matrixDirty = true; |
|
1293 } |
|
1294 |
|
1295 d->setBrush(brush); |
999 d->setBrush(brush); |
1296 d->fill(path); |
1000 d->fill(path); |
1297 |
|
1298 if (doOffset) { |
|
1299 s->matrix = d->temporaryTransform; |
|
1300 d->matrixDirty = true; |
|
1301 } |
|
1302 } |
1001 } |
1303 |
1002 |
1304 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp |
1003 extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp |
1305 |
1004 |
1306 |
1005 |
1307 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) |
1006 void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) |
1308 { |
1007 { |
1309 Q_D(QGL2PaintEngineEx); |
1008 Q_D(QGL2PaintEngineEx); |
1310 |
1009 |
1311 Qt::PenStyle penStyle = qpen_style(pen); |
|
1312 const QBrush &penBrush = qpen_brush(pen); |
1010 const QBrush &penBrush = qpen_brush(pen); |
1313 if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) |
1011 if (qpen_style(pen) == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) |
1314 return; |
1012 return; |
1315 |
1013 |
1316 QOpenGL2PaintEngineState *s = state(); |
1014 QOpenGL2PaintEngineState *s = state(); |
1317 if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) { |
1015 if (pen.isCosmetic() && !qt_scaleForTransform(s->transform(), 0)) { |
1318 // QTriangulatingStroker class is not meant to support cosmetically sheared strokes. |
1016 // QTriangulatingStroker class is not meant to support cosmetically sheared strokes. |
1319 QPaintEngineEx::stroke(path, pen); |
1017 QPaintEngineEx::stroke(path, pen); |
1320 return; |
1018 return; |
1321 } |
1019 } |
1322 |
1020 |
1323 ensureActive(); |
1021 ensureActive(); |
1324 |
|
1325 bool doOffset = !(s->renderHints & QPainter::Antialiasing) && !d->multisamplingAlwaysEnabled; |
|
1326 if (doOffset) { |
|
1327 d->temporaryTransform = s->matrix; |
|
1328 QTransform tx = QTransform::fromTranslate(0.49, .49); |
|
1329 s->matrix = s->matrix * tx; |
|
1330 d->matrixDirty = true; |
|
1331 } |
|
1332 |
|
1333 bool opaque = penBrush.isOpaque() && s->opacity > 0.99; |
|
1334 d->setBrush(penBrush); |
1022 d->setBrush(penBrush); |
1335 d->transferMode(BrushDrawingMode); |
1023 d->stroke(path, pen); |
|
1024 } |
|
1025 |
|
1026 void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen) |
|
1027 { |
|
1028 const QOpenGL2PaintEngineState *s = q->state(); |
|
1029 const bool newAddOffset = !(s->renderHints & QPainter::Antialiasing) && !multisamplingAlwaysEnabled; |
|
1030 if (addOffset != newAddOffset) { |
|
1031 addOffset = newAddOffset; |
|
1032 matrixDirty = true; |
|
1033 } |
|
1034 |
|
1035 if (snapToPixelGrid) { |
|
1036 snapToPixelGrid = false; |
|
1037 matrixDirty = true; |
|
1038 } |
|
1039 |
|
1040 const Qt::PenStyle penStyle = qpen_style(pen); |
|
1041 const QBrush &penBrush = qpen_brush(pen); |
|
1042 const bool opaque = penBrush.isOpaque() && s->opacity > 0.99; |
|
1043 |
|
1044 transferMode(BrushDrawingMode); |
1336 |
1045 |
1337 // updateMatrix() is responsible for setting the inverse scale on |
1046 // updateMatrix() is responsible for setting the inverse scale on |
1338 // the strokers, so we need to call it here and not wait for |
1047 // the strokers, so we need to call it here and not wait for |
1339 // prepareForDraw() down below. |
1048 // prepareForDraw() down below. |
1340 d->updateMatrix(); |
1049 updateMatrix(); |
1341 |
1050 |
1342 if (penStyle == Qt::SolidLine) { |
1051 if (penStyle == Qt::SolidLine) { |
1343 d->stroker.process(path, pen); |
1052 stroker.process(path, pen); |
1344 |
1053 |
1345 } else { // Some sort of dash |
1054 } else { // Some sort of dash |
1346 d->dasher.process(path, pen); |
1055 dasher.process(path, pen); |
1347 |
1056 |
1348 QVectorPath dashStroke(d->dasher.points(), |
1057 QVectorPath dashStroke(dasher.points(), |
1349 d->dasher.elementCount(), |
1058 dasher.elementCount(), |
1350 d->dasher.elementTypes()); |
1059 dasher.elementTypes()); |
1351 d->stroker.process(dashStroke, pen); |
1060 stroker.process(dashStroke, pen); |
1352 } |
1061 } |
1353 |
|
1354 |
|
1355 QGLContext *ctx = d->ctx; |
|
1356 Q_UNUSED(ctx); |
|
1357 |
1062 |
1358 if (opaque) { |
1063 if (opaque) { |
1359 d->prepareForDraw(opaque); |
1064 prepareForDraw(opaque); |
1360 glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
1065 setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, stroker.vertices()); |
1361 glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, d->stroker.vertices()); |
1066 glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2); |
1362 glDrawArrays(GL_TRIANGLE_STRIP, 0, d->stroker.vertexCount() / 2); |
|
1363 |
1067 |
1364 // QBrush b(Qt::green); |
1068 // QBrush b(Qt::green); |
1365 // d->setBrush(&b); |
1069 // d->setBrush(&b); |
1366 // d->prepareForDraw(true); |
1070 // d->prepareForDraw(true); |
1367 // glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2); |
1071 // glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2); |
1368 |
|
1369 glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); |
|
1370 |
1072 |
1371 } else { |
1073 } else { |
1372 qreal width = qpen_widthf(pen) / 2; |
1074 qreal width = qpen_widthf(pen) / 2; |
1373 if (width == 0) |
1075 if (width == 0) |
1374 width = 0.5; |
1076 width = 0.5; |
1375 qreal extra = pen.joinStyle() == Qt::MiterJoin |
1077 qreal extra = pen.joinStyle() == Qt::MiterJoin |
1376 ? qMax(pen.miterLimit() * width, width) |
1078 ? qMax(pen.miterLimit() * width, width) |
1377 : width; |
1079 : width; |
1378 |
1080 |
1379 if (pen.isCosmetic()) |
1081 if (pen.isCosmetic()) |
1380 extra = extra * d->inverseScale; |
1082 extra = extra * inverseScale; |
1381 |
1083 |
1382 QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); |
1084 QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); |
1383 |
1085 |
1384 d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2, |
1086 fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2, |
1385 0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode); |
1087 0, 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode); |
1386 |
1088 |
1387 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); |
1089 glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); |
1388 |
1090 |
1389 // Pass when any bit is set, replace stencil value with 0 |
1091 // Pass when any bit is set, replace stencil value with 0 |
1390 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); |
1092 glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); |
1391 d->prepareForDraw(false); |
1093 prepareForDraw(false); |
1392 |
1094 |
1393 // Stencil the brush onto the dest buffer |
1095 // Stencil the brush onto the dest buffer |
1394 d->composite(bounds); |
1096 composite(bounds); |
1395 |
1097 |
1396 glStencilMask(0); |
1098 glStencilMask(0); |
1397 |
1099 |
1398 d->updateClipScissorTest(); |
1100 updateClipScissorTest(); |
1399 } |
|
1400 |
|
1401 if (doOffset) { |
|
1402 s->matrix = d->temporaryTransform; |
|
1403 d->matrixDirty = true; |
|
1404 } |
1101 } |
1405 } |
1102 } |
1406 |
1103 |
1407 void QGL2PaintEngineEx::penChanged() { } |
1104 void QGL2PaintEngineEx::penChanged() { } |
1408 void QGL2PaintEngineEx::brushChanged() { } |
1105 void QGL2PaintEngineEx::brushChanged() { } |
1697 glBindTexture(GL_TEXTURE_2D, cache->texture()); |
1392 glBindTexture(GL_TEXTURE_2D, cache->texture()); |
1698 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); |
1393 updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); |
1699 |
1394 |
1700 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); |
1395 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT); |
1701 glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); |
1396 glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size()); |
1702 |
|
1703 if (inRenderText) |
|
1704 restoreDepthRangeForRenderText(); |
|
1705 } |
1397 } |
1706 |
1398 |
1707 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) |
1399 void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) |
1708 { |
1400 { |
|
1401 Q_D(QGL2PaintEngineEx); |
1709 // Use fallback for extended composition modes. |
1402 // Use fallback for extended composition modes. |
1710 if (state()->composition_mode > QPainter::CompositionMode_Plus) { |
1403 if (state()->composition_mode > QPainter::CompositionMode_Plus) { |
1711 QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints); |
1404 QPaintEngineEx::drawPixmaps(drawingData, dataCount, pixmap, hints); |
1712 return; |
1405 return; |
1713 } |
1406 } |
1714 |
1407 |
1715 Q_D(QGL2PaintEngineEx); |
1408 ensureActive(); |
1716 |
1409 d->drawPixmaps(drawingData, dataCount, pixmap, hints); |
|
1410 } |
|
1411 |
|
1412 |
|
1413 void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints) |
|
1414 { |
1717 GLfloat dx = 1.0f / pixmap.size().width(); |
1415 GLfloat dx = 1.0f / pixmap.size().width(); |
1718 GLfloat dy = 1.0f / pixmap.size().height(); |
1416 GLfloat dy = 1.0f / pixmap.size().height(); |
1719 |
1417 |
1720 d->vertexCoordinateArray.clear(); |
1418 vertexCoordinateArray.clear(); |
1721 d->textureCoordinateArray.clear(); |
1419 textureCoordinateArray.clear(); |
1722 d->opacityArray.reset(); |
1420 opacityArray.reset(); |
|
1421 |
|
1422 if (addOffset) { |
|
1423 addOffset = false; |
|
1424 matrixDirty = true; |
|
1425 } |
|
1426 |
|
1427 if (snapToPixelGrid) { |
|
1428 snapToPixelGrid = false; |
|
1429 matrixDirty = true; |
|
1430 } |
1723 |
1431 |
1724 bool allOpaque = true; |
1432 bool allOpaque = true; |
1725 |
1433 |
1726 for (int i = 0; i < dataCount; ++i) { |
1434 for (int i = 0; i < dataCount; ++i) { |
1727 qreal s = 0; |
1435 qreal s = 0; |
1734 qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width(); |
1442 qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width(); |
1735 qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height(); |
1443 qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height(); |
1736 QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c); |
1444 QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c); |
1737 QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c); |
1445 QGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c); |
1738 |
1446 |
1739 d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); |
1447 vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); |
1740 d->vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y()); |
1448 vertexCoordinateArray.lineToArray(-bottomLeft.x + drawingData[i].point.x(), -bottomLeft.y + drawingData[i].point.y()); |
1741 d->vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); |
1449 vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); |
1742 d->vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); |
1450 vertexCoordinateArray.lineToArray(-bottomRight.x + drawingData[i].point.x(), -bottomRight.y + drawingData[i].point.y()); |
1743 d->vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y()); |
1451 vertexCoordinateArray.lineToArray(bottomLeft.x + drawingData[i].point.x(), bottomLeft.y + drawingData[i].point.y()); |
1744 d->vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); |
1452 vertexCoordinateArray.lineToArray(bottomRight.x + drawingData[i].point.x(), bottomRight.y + drawingData[i].point.y()); |
1745 |
1453 |
1746 QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy, |
1454 QGLRect src(drawingData[i].source.left() * dx, drawingData[i].source.top() * dy, |
1747 drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy); |
1455 drawingData[i].source.right() * dx, drawingData[i].source.bottom() * dy); |
1748 |
1456 |
1749 d->textureCoordinateArray.lineToArray(src.right, src.bottom); |
1457 textureCoordinateArray.lineToArray(src.right, src.bottom); |
1750 d->textureCoordinateArray.lineToArray(src.right, src.top); |
1458 textureCoordinateArray.lineToArray(src.right, src.top); |
1751 d->textureCoordinateArray.lineToArray(src.left, src.top); |
1459 textureCoordinateArray.lineToArray(src.left, src.top); |
1752 d->textureCoordinateArray.lineToArray(src.left, src.top); |
1460 textureCoordinateArray.lineToArray(src.left, src.top); |
1753 d->textureCoordinateArray.lineToArray(src.left, src.bottom); |
1461 textureCoordinateArray.lineToArray(src.left, src.bottom); |
1754 d->textureCoordinateArray.lineToArray(src.right, src.bottom); |
1462 textureCoordinateArray.lineToArray(src.right, src.bottom); |
1755 |
1463 |
1756 qreal opacity = drawingData[i].opacity * state()->opacity; |
1464 qreal opacity = drawingData[i].opacity * q->state()->opacity; |
1757 d->opacityArray << opacity << opacity << opacity << opacity << opacity << opacity; |
1465 opacityArray << opacity << opacity << opacity << opacity << opacity << opacity; |
1758 allOpaque &= (opacity >= 0.99f); |
1466 allOpaque &= (opacity >= 0.99f); |
1759 } |
1467 } |
1760 |
1468 |
1761 ensureActive(); |
|
1762 |
|
1763 QGLContext *ctx = d->ctx; |
|
1764 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); |
1469 glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); |
1765 QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, |
1470 QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, |
1766 QGLContext::InternalBindOption |
1471 QGLContext::InternalBindOption |
1767 | QGLContext::CanFlipNativePixmapBindOption); |
1472 | QGLContext::CanFlipNativePixmapBindOption); |
1768 |
1473 |
1769 if (texture->options & QGLContext::InvertedYBindOption) { |
1474 if (texture->options & QGLContext::InvertedYBindOption) { |
1770 // Flip texture y-coordinate. |
1475 // Flip texture y-coordinate. |
1771 QGLPoint *data = d->textureCoordinateArray.data(); |
1476 QGLPoint *data = textureCoordinateArray.data(); |
1772 for (int i = 0; i < 6 * dataCount; ++i) |
1477 for (int i = 0; i < 6 * dataCount; ++i) |
1773 data[i].y = 1 - data[i].y; |
1478 data[i].y = 1 - data[i].y; |
1774 } |
1479 } |
1775 |
1480 |
1776 d->transferMode(ImageArrayDrawingMode); |
1481 transferMode(ImageArrayDrawingMode); |
1777 |
1482 |
1778 bool isBitmap = pixmap.isQBitmap(); |
1483 bool isBitmap = pixmap.isQBitmap(); |
1779 bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque; |
1484 bool isOpaque = !isBitmap && (!pixmap.hasAlphaChannel() || (hints & QDrawPixmaps::OpaqueHint)) && allOpaque; |
1780 |
1485 |
1781 d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, |
1486 updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, |
1782 state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); |
1487 q->state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); |
1783 |
1488 |
1784 // Setup for texture drawing |
1489 // Setup for texture drawing |
1785 d->shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); |
1490 currentBrush = noBrush; |
1786 if (d->prepareForDraw(isOpaque)) |
1491 shaderManager->setSrcPixelType(isBitmap ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc); |
1787 d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); |
1492 if (prepareForDraw(isOpaque)) |
|
1493 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); |
1788 |
1494 |
1789 if (isBitmap) { |
1495 if (isBitmap) { |
1790 QColor col = qt_premultiplyColor(state()->pen.color(), (GLfloat)state()->opacity); |
1496 QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); |
1791 d->shaderManager->currentProgram()->setUniformValue(d->location(QGLEngineShaderManager::PatternColor), col); |
1497 shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col); |
1792 } |
1498 } |
1793 |
1499 |
1794 glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount); |
1500 glDrawArrays(GL_TRIANGLES, 0, 6 * dataCount); |
1795 } |
1501 } |
1796 |
1502 |