Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qopengltextureblitter.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <QtOpenGL/QOpenGLShaderProgram>
8#include <QtOpenGL/QOpenGLVertexArrayObject>
9#include <QtOpenGL/QOpenGLBuffer>
10#include <QtGui/QOpenGLContext>
11#include <QtGui/QOpenGLFunctions>
12#include <QtGui/QOpenGLExtraFunctions>
13
14#ifndef GL_TEXTURE_EXTERNAL_OES
15#define GL_TEXTURE_EXTERNAL_OES 0x8D65
16#endif
17#ifndef GL_TEXTURE_RECTANGLE
18#define GL_TEXTURE_RECTANGLE 0x84F5
19#endif
20#ifndef GL_TEXTURE_WIDTH
21#define GL_TEXTURE_WIDTH 0x1000
22#endif
23#ifndef GL_TEXTURE_HEIGHT
24#define GL_TEXTURE_HEIGHT 0x1001
25#endif
26
28
29/*!
30 \class QOpenGLTextureBlitter
31 \brief The QOpenGLTextureBlitter class provides a convenient way to draw textured quads via OpenGL.
32 \since 5.8
33 \ingroup painting-3D
34 \inmodule QtOpenGL
35
36 Drawing textured quads, in order to get the contents of a texture
37 onto the screen, is a common operation when developing 2D user
38 interfaces. QOpenGLTextureBlitter provides a convenience class to
39 avoid repeating vertex data, shader sources, buffer and program
40 management and matrix calculations.
41
42 For example, a QOpenGLWidget subclass can do the following to draw
43 the contents rendered into a framebuffer at the pixel position \c{(x, y)}:
44
45 \code
46 void OpenGLWidget::initializeGL()
47 {
48 m_blitter.create();
49 m_fbo = new QOpenGLFramebufferObject(size);
50 }
51
52 void OpenGLWidget::paintGL()
53 {
54 m_fbo->bind();
55 // update offscreen content
56 m_fbo->release();
57
58 m_blitter.bind();
59 const QRect targetRect(QPoint(x, y), m_fbo->size());
60 const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, QRect(QPoint(0, 0), m_fbo->size()));
61 m_blitter.blit(m_fbo->texture(), target, QOpenGLTextureBlitter::OriginBottomLeft);
62 m_blitter.release();
63 }
64 \endcode
65
66 The blitter implements GLSL shaders both for GLSL 1.00 (suitable
67 for OpenGL (ES) 2.x and compatibility profiles of newer OpenGL
68 versions) and version 150 (suitable for core profile contexts with
69 OpenGL 3.2 and newer).
70 */
71
72static const char vertex_shader150[] =
73 "#version 150 core\n"
74 "in vec3 vertexCoord;"
75 "in vec2 textureCoord;"
76 "out vec2 uv;"
77 "uniform mat4 vertexTransform;"
78 "uniform mat3 textureTransform;"
79 "void main() {"
80 " uv = (textureTransform * vec3(textureCoord,1.0)).xy;"
81 " gl_Position = vertexTransform * vec4(vertexCoord,1.0);"
82 "}";
83
84static const char fragment_shader150[] =
85 "#version 150 core\n"
86 "in vec2 uv;"
87 "out vec4 fragcolor;"
88 "uniform sampler2D textureSampler;"
89 "uniform bool swizzle;"
90 "uniform float opacity;"
91 "void main() {"
92 " vec4 tmpFragColor = texture(textureSampler, uv);"
93 " tmpFragColor.a *= opacity;"
94 " fragcolor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
95 "}";
96
97static const char vertex_shader[] =
98 "attribute highp vec3 vertexCoord;"
99 "attribute highp vec2 textureCoord;"
100 "varying highp vec2 uv;"
101 "uniform highp mat4 vertexTransform;"
102 "uniform highp mat3 textureTransform;"
103 "void main() {"
104 " uv = (textureTransform * vec3(textureCoord,1.0)).xy;"
105 " gl_Position = vertexTransform * vec4(vertexCoord,1.0);"
106 "}";
107
108static const char fragment_shader[] =
109 "varying highp vec2 uv;"
110 "uniform sampler2D textureSampler;"
111 "uniform bool swizzle;"
112 "uniform highp float opacity;"
113 "void main() {"
114 " highp vec4 tmpFragColor = texture2D(textureSampler,uv);"
115 " tmpFragColor.a *= opacity;"
116 " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
117 "}";
118
119static const char fragment_shader_external_oes[] =
120 "#extension GL_OES_EGL_image_external : require\n"
121 "varying highp vec2 uv;"
122 "uniform samplerExternalOES textureSampler;\n"
123 "uniform bool swizzle;"
124 "uniform highp float opacity;"
125 "void main() {"
126 " highp vec4 tmpFragColor = texture2D(textureSampler, uv);"
127 " tmpFragColor.a *= opacity;"
128 " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
129 "}";
130
131static const char fragment_shader_rectangle[] =
132 "varying highp vec2 uv;"
133 "uniform sampler2DRect textureSampler;"
134 "uniform bool swizzle;"
135 "uniform highp float opacity;"
136 "void main() {"
137 " highp vec4 tmpFragColor = texture2DRect(textureSampler,uv);"
138 " tmpFragColor.a *= opacity;"
139 " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
140 "}";
141
142static const char fragment_shader150_rectangle[] =
143 "#version 150 core\n"
144 "in vec2 uv;"
145 "out vec4 fragcolor;"
146 "uniform sampler2DRect textureSampler;"
147 "uniform bool swizzle;"
148 "uniform float opacity;"
149 "void main() {"
150 " vec4 tmpFragColor = texture(textureSampler, uv);"
151 " tmpFragColor.a *= opacity;"
152 " fragcolor = swizzle ? tmpFragColor.bgra : tmpFragColor;"
153 "}";
154
155static const GLfloat vertex_buffer_data[] = {
156 -1,-1, 0,
157 -1, 1, 0,
158 1,-1, 0,
159 -1, 1, 0,
160 1,-1, 0,
161 1, 1, 0
162};
163
164static const GLfloat texture_buffer_data[] = {
165 0, 0,
166 0, 1,
167 1, 0,
168 0, 1,
169 1, 0,
170 1, 1
171};
172
174{
175public:
176 explicit QBlitterTextureBinder(GLenum target, GLuint textureId) : m_target(target)
177 {
178 QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, textureId);
179 }
181 {
182 QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, 0);
183 }
184
185private:
186 GLenum m_target;
187};
188
190{
191public:
197
203
204 QOpenGLTextureBlitterPrivate(QOpenGLTextureBlitter *q_ptr) :
205 q(q_ptr),
206 swizzle(false),
207 opacity(1.0f),
210 { }
211
212 bool buildProgram(ProgramIndex idx, const char *vs, const char *fs);
214
215 void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform);
216 void blit(GLuint texture, const QMatrix4x4 &targetTransform, QOpenGLTextureBlitter::Origin origin);
217
218 QMatrix3x3 toTextureCoordinates(const QMatrix3x3 &sourceTransform) const;
219
220 bool prepareProgram(const QMatrix4x4 &vertexTransform);
221
249 float opacity;
252};
253
255{
256 switch (target) {
257 case GL_TEXTURE_2D:
263 default:
264 qWarning("Unsupported texture target 0x%x", target);
266 }
267}
268
269bool QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransform)
270{
271 ProgramIndex programIndex = targetToProgramIndex(currentTarget);
272 if (!ensureProgram(programIndex))
273 return false;
274
275 Program *program = &programs[programIndex];
276
277 vertexBuffer.bind();
278 program->glProgram->setAttributeBuffer(program->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0);
279 program->glProgram->enableAttributeArray(program->vertexCoordAttribPos);
280 vertexBuffer.release();
281
282 program->glProgram->setUniformValue(program->vertexTransformUniformPos, vertexTransform);
283
284 textureBuffer.bind();
285 program->glProgram->setAttributeBuffer(program->textureCoordAttribPos, GL_FLOAT, 0, 2, 0);
286 program->glProgram->enableAttributeArray(program->textureCoordAttribPos);
287 textureBuffer.release();
288
289 if (swizzle != program->swizzle) {
290 program->glProgram->setUniformValue(program->swizzleUniformPos, swizzle);
291 program->swizzle = swizzle;
292 }
293
294 if (opacity != program->opacity) {
295 program->glProgram->setUniformValue(program->opacityUniformPos, opacity);
296 program->opacity = opacity;
297 }
298
299 return true;
300}
301
302QMatrix3x3 QOpenGLTextureBlitterPrivate::toTextureCoordinates(const QMatrix3x3 &sourceTransform) const
303{
304 if (currentTarget == GL_TEXTURE_RECTANGLE) {
305 // Non-normalized coordinates
306 QMatrix4x4 textureTransform(sourceTransform);
307 if (auto *glFunctions = QOpenGLContext::currentContext()->extraFunctions()) {
308 int width, height;
309 glFunctions->glGetTexLevelParameteriv(currentTarget, 0, GL_TEXTURE_WIDTH, &width);
310 glFunctions->glGetTexLevelParameteriv(currentTarget, 0, GL_TEXTURE_HEIGHT, &height);
311 textureTransform.scale(width, height);
312 }
313 return textureTransform.toGenericMatrix<3, 3>();
314 }
315
316 return sourceTransform; // Normalized coordinates
317}
318
320 const QMatrix4x4 &targetTransform,
321 const QMatrix3x3 &sourceTransform)
322{
323 QBlitterTextureBinder binder(currentTarget, texture);
324 if (!prepareProgram(targetTransform))
325 return;
326
327 Program *program = &programs[targetToProgramIndex(currentTarget)];
328
329 const QMatrix3x3 textureTransform = toTextureCoordinates(sourceTransform);
330 program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform);
332
333 QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6);
334}
335
337 const QMatrix4x4 &targetTransform,
338 QOpenGLTextureBlitter::Origin origin)
339{
340 QBlitterTextureBinder binder(currentTarget, texture);
341 if (!prepareProgram(targetTransform))
342 return;
343
344 Program *program = &programs[targetToProgramIndex(currentTarget)];
345
346 if (origin == QOpenGLTextureBlitter::OriginTopLeft) {
348 QMatrix3x3 sourceTransform;
349 sourceTransform(1,1) = -1;
350 sourceTransform(1,2) = 1;
351 const QMatrix3x3 textureTransform = toTextureCoordinates(sourceTransform);
352 program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform);
354 }
355 } else if (program->textureMatrixUniformState != Identity) {
356 const QMatrix3x3 textureTransform = toTextureCoordinates(QMatrix3x3());
357 program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform);
359 }
360
361 QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6);
362}
363
364bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs, const char *fs)
365{
366 Program *p = &programs[idx];
367
368 p->glProgram.reset(new QOpenGLShaderProgram);
369
370 p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vs);
371 p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fs);
372 p->glProgram->link();
373 if (!p->glProgram->isLinked()) {
374 qWarning() << "Could not link shader program:\n" << p->glProgram->log();
375 return false;
376 }
377
378 p->glProgram->bind();
379
380 p->vertexCoordAttribPos = p->glProgram->attributeLocation("vertexCoord");
381 p->vertexTransformUniformPos = p->glProgram->uniformLocation("vertexTransform");
382 p->textureCoordAttribPos = p->glProgram->attributeLocation("textureCoord");
383 p->textureTransformUniformPos = p->glProgram->uniformLocation("textureTransform");
384 p->swizzleUniformPos = p->glProgram->uniformLocation("swizzle");
385 p->opacityUniformPos = p->glProgram->uniformLocation("opacity");
386
387 p->glProgram->setUniformValue(p->swizzleUniformPos, false);
388
389 // minmize state left set after a create()
390 p->glProgram->release();
391
392 return true;
393}
394
396{
397 if (programs[idx].glProgram)
398 return true;
399
400 QOpenGLContext *currentContext = QOpenGLContext::currentContext();
401 if (!currentContext)
402 return false;
403
404 QSurfaceFormat format = currentContext->format();
405 if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= std::pair(3,2)) {
406 if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE && q->supportsRectangleTarget()) {
408 return false;
409 }
410 } else {
411 if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE && q->supportsRectangleTarget()) {
413 return false;
414 }
415 if (idx == QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES && q->supportsExternalOESTarget()) {
417 return false;
418 }
419 }
420
421 return !programs[idx].glProgram.isNull();
422}
423
424/*!
425 Constructs a new QOpenGLTextureBlitter instance.
426
427 \note no graphics resources are initialized in the
428 constructor. This makes it safe to place plain
429 QOpenGLTextureBlitter members into classes because the actual
430 initialization that depends on the OpenGL context happens only in
431 create().
432 */
433QOpenGLTextureBlitter::QOpenGLTextureBlitter()
434 : d_ptr(new QOpenGLTextureBlitterPrivate(this))
435{
436}
437
438/*!
439 Destructs the instance.
440
441 \note When the OpenGL context - or a context sharing resources
442 with it - that was current when calling create() is not current,
443 graphics resources will not be released. Therefore, it is
444 recommended to call destroy() manually instead of relying on the
445 destructor to perform OpenGL resource cleanup.
446 */
447QOpenGLTextureBlitter::~QOpenGLTextureBlitter()
448{
449 destroy();
450}
451
452/*!
453 Initializes the graphics resources used by the blitter.
454
455 \return \c true if successful, \c false if there was a
456 failure. Failures can occur when there is no OpenGL context
457 current on the current thread, or when shader compilation fails
458 for some reason.
459
460 \sa isCreated(), destroy()
461 */
462bool QOpenGLTextureBlitter::create()
463{
464 QOpenGLContext *currentContext = QOpenGLContext::currentContext();
465 if (!currentContext)
466 return false;
467
468 Q_D(QOpenGLTextureBlitter);
469
470 if (d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram)
471 return true;
472
473 QSurfaceFormat format = currentContext->format();
474 // Build the most common, 2D texture shader variant.
475 // The other special ones are deferred and compiled only when first needed.
476 if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= std::pair(3,2)) {
477 if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader150, fragment_shader150))
478 return false;
479 } else {
480 if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader, fragment_shader))
481 return false;
482 }
483
484 // Create and bind the VAO, if supported.
485 QOpenGLVertexArrayObject::Binder vaoBinder(d->vao.data());
486
487 d->vertexBuffer.create();
488 d->vertexBuffer.bind();
489 d->vertexBuffer.allocate(vertex_buffer_data, sizeof(vertex_buffer_data));
490 d->vertexBuffer.release();
491
492 d->textureBuffer.create();
493 d->textureBuffer.bind();
494 d->textureBuffer.allocate(texture_buffer_data, sizeof(texture_buffer_data));
495 d->textureBuffer.release();
496
497 return true;
498}
499
500/*!
501 \return \c true if create() was called and succeeded. \c false otherwise.
502
503 \sa create(), destroy()
504 */
505bool QOpenGLTextureBlitter::isCreated() const
506{
507 Q_D(const QOpenGLTextureBlitter);
508 return !d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.isNull();
509}
510
511/*!
512 Frees all graphics resources held by the blitter. Assumes that
513 the OpenGL context, or another context sharing resources with it,
514 that was current on the thread when invoking create() is current.
515
516 The function has no effect when the blitter is not in created state.
517
518 \sa create()
519 */
520void QOpenGLTextureBlitter::destroy()
521{
522 if (!isCreated())
523 return;
524 Q_D(QOpenGLTextureBlitter);
525 d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.reset();
526 d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES].glProgram.reset();
527 d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE].glProgram.reset();
528 d->vertexBuffer.destroy();
529 d->textureBuffer.destroy();
530 d->vao.reset();
531}
532
533/*!
534 \return \c true when bind() accepts \c GL_TEXTURE_EXTERNAL_OES as
535 its target argument.
536
537 \sa bind(), blit()
538 */
539bool QOpenGLTextureBlitter::supportsExternalOESTarget() const
540{
541 QOpenGLContext *ctx = QOpenGLContext::currentContext();
542 return ctx && ctx->isOpenGLES() && ctx->hasExtension("GL_OES_EGL_image_external");
543}
544
545/*!
546 \return \c true when bind() accepts \c GL_TEXTURE_RECTANGLE as
547 its target argument.
548
549 \sa bind(), blit()
550 */
551bool QOpenGLTextureBlitter::supportsRectangleTarget() const
552{
553 QOpenGLContext *ctx = QOpenGLContext::currentContext();
554 if (!ctx || ctx->isOpenGLES())
555 return false;
556
557 if (ctx->hasExtension("GL_ARB_texture_rectangle"))
558 return true;
559
560 if (ctx->hasExtension("GL_EXT_texture_rectangle"))
561 return true;
562
563 QSurfaceFormat f = ctx->format();
564 const auto version = std::pair(f.majorVersion(), f.minorVersion());
565 if (version >= std::pair(3, 1))
566 return true;
567
568 return false;
569}
570
571/*!
572 Binds the graphics resources used by the blitter. This must be
573 called before calling blit(). Code modifying the OpenGL state
574 should be avoided between the call to bind() and blit() because
575 otherwise conflicts may arise.
576
577 \a target is the texture target for the source texture and must be
578 either \c GL_TEXTURE_2D, \c GL_TEXTURE_RECTANGLE, or \c GL_OES_EGL_image_external.
579
580 \sa release(), blit()
581 */
582void QOpenGLTextureBlitter::bind(GLenum target)
583{
584 Q_D(QOpenGLTextureBlitter);
585
586 if (d->vao->isCreated())
587 d->vao->bind();
588
589 d->currentTarget = target;
590 QOpenGLTextureBlitterPrivate::ProgramIndex programIndex = targetToProgramIndex(target);
591 if (!d->ensureProgram(programIndex))
592 return;
593
594 QOpenGLTextureBlitterPrivate::Program *p = &d->programs[programIndex];
595 p->glProgram->bind();
596
597 d->vertexBuffer.bind();
598 p->glProgram->setAttributeBuffer(p->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0);
599 p->glProgram->enableAttributeArray(p->vertexCoordAttribPos);
600 d->vertexBuffer.release();
601
602 d->textureBuffer.bind();
603 p->glProgram->setAttributeBuffer(p->textureCoordAttribPos, GL_FLOAT, 0, 2, 0);
604 p->glProgram->enableAttributeArray(p->textureCoordAttribPos);
605 d->textureBuffer.release();
606}
607
608/*!
609 Unbinds the graphics resources used by the blitter.
610
611 \sa bind()
612 */
613void QOpenGLTextureBlitter::release()
614{
615 Q_D(QOpenGLTextureBlitter);
616 QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(d->currentTarget)];
617 if (p->glProgram)
618 p->glProgram->release();
619 if (d->vao->isCreated())
620 d->vao->release();
621}
622
623/*!
624 Sets whether swizzling is enabled for the red and blue color channels to
625 \a swizzle. An BGRA to RGBA conversion (occurring in the shader on
626 the GPU, instead of a slow CPU-side transformation) can be useful
627 when the source texture contains data from a QImage with a format
628 like QImage::Format_ARGB32 which maps to BGRA on little endian
629 systems.
630
631 By default the red-blue swizzle is disabled since this is what a
632 texture attached to an framebuffer object or a texture based on a
633 byte ordered QImage format (like QImage::Format_RGBA8888) needs.
634 */
635void QOpenGLTextureBlitter::setRedBlueSwizzle(bool swizzle)
636{
637 Q_D(QOpenGLTextureBlitter);
638 d->swizzle = swizzle;
639}
640
641/*!
642 Changes the opacity to \a opacity. The default opacity is 1.0.
643
644 \note the blitter does not alter the blend state. It is up to the
645 caller of blit() to ensure the correct blend settings are active.
646
647 */
648void QOpenGLTextureBlitter::setOpacity(float opacity)
649{
650 Q_D(QOpenGLTextureBlitter);
651 d->opacity = opacity;
652}
653
654/*!
655 \enum QOpenGLTextureBlitter::Origin
656
657 \value OriginBottomLeft Indicates that the data in the texture
658 follows the OpenGL convention of coordinate systems, meaning Y is
659 running from bottom to top.
660
661 \value OriginTopLeft Indicates that the data in the texture has Y
662 running from top to bottom, which is typical with regular,
663 unflipped image data.
664
665 \sa blit()
666 */
667
668/*!
669 Performs the blit with the source texture \a texture.
670
671 \a targetTransform specifies the transformation applied. This is
672 usually generated by the targetTransform() helper function.
673
674 \a sourceOrigin specifies if the image data needs flipping. When
675 \a texture corresponds to a texture attached to an FBO pass
676 OriginBottomLeft. On the other hand, when \a texture is based on
677 unflipped image data, pass OriginTopLeft. This is more efficient
678 than using QImage::flipped().
679
680 \sa targetTransform(), Origin, bind()
681 */
682void QOpenGLTextureBlitter::blit(GLuint texture,
683 const QMatrix4x4 &targetTransform,
684 Origin sourceOrigin)
685{
686 Q_D(QOpenGLTextureBlitter);
687 d->blit(texture, targetTransform, sourceOrigin);
688}
689
690/*!
691 Performs the blit with the source texture \a texture.
692
693 \a targetTransform specifies the transformation applied. This is
694 usually generated by the targetTransform() helper function.
695
696 \a sourceTransform specifies the transformation applied to the
697 source. This allows using only a sub-rect of the source
698 texture. This is usually generated by the sourceTransform() helper
699 function.
700
701 \sa sourceTransform(), targetTransform(), Origin, bind()
702 */
703void QOpenGLTextureBlitter::blit(GLuint texture,
704 const QMatrix4x4 &targetTransform,
705 const QMatrix3x3 &sourceTransform)
706{
707 Q_D(QOpenGLTextureBlitter);
708 d->blit(texture, targetTransform, sourceTransform);
709}
710
711/*!
712 Calculates a target transform suitable for blit().
713
714 \a target is the target rectangle in pixels. \a viewport describes
715 the source dimensions and will in most cases be set to (0, 0,
716 image width, image height).
717
718 For unscaled output the size of \a target and \a viewport should
719 match.
720
721 \sa blit()
722 */
723QMatrix4x4 QOpenGLTextureBlitter::targetTransform(const QRectF &target,
724 const QRect &viewport)
725{
726 qreal x_scale = target.width() / viewport.width();
727 qreal y_scale = target.height() / viewport.height();
728
729 const QPointF relative_to_viewport = target.topLeft() - viewport.topLeft();
730 qreal x_translate = x_scale - 1 + ((relative_to_viewport.x() / viewport.width()) * 2);
731 qreal y_translate = -y_scale + 1 - ((relative_to_viewport.y() / viewport.height()) * 2);
732
733 QMatrix4x4 matrix;
734 matrix(0,3) = x_translate;
735 matrix(1,3) = y_translate;
736
737 matrix(0,0) = x_scale;
738 matrix(1,1) = y_scale;
739
740 return matrix;
741}
742
743/*!
744 Calculates a 3x3 matrix suitable as the input to blit(). This is
745 used when only a part of the texture is to be used in the blit.
746
747 \a subTexture is the desired source rectangle in pixels, \a
748 textureSize is the full width and height of the texture data. \a
749 origin specifies the orientation of the image data when it comes
750 to the Y axis.
751
752 \sa blit(), Origin
753 */
754QMatrix3x3 QOpenGLTextureBlitter::sourceTransform(const QRectF &subTexture,
755 const QSize &textureSize,
756 Origin origin)
757{
758 qreal x_scale = subTexture.width() / textureSize.width();
759 qreal y_scale = subTexture.height() / textureSize.height();
760
761 const QPointF topLeft = subTexture.topLeft();
762 qreal x_translate = topLeft.x() / textureSize.width();
763 qreal y_translate = topLeft.y() / textureSize.height();
764
765 if (origin == OriginTopLeft) {
766 y_scale = -y_scale;
767 y_translate = 1 - y_translate;
768 }
769
770 QMatrix3x3 matrix;
771 matrix(0,2) = x_translate;
772 matrix(1,2) = y_translate;
773
774 matrix(0,0) = x_scale;
775 matrix(1,1) = y_scale;
776
777 return matrix;
778}
779
780QT_END_NAMESPACE
QBlitterTextureBinder(GLenum target, GLuint textureId)
QMatrix3x3 toTextureCoordinates(const QMatrix3x3 &sourceTransform) const
void blit(GLuint texture, const QMatrix4x4 &targetTransform, QOpenGLTextureBlitter::Origin origin)
QOpenGLTextureBlitterPrivate(QOpenGLTextureBlitter *q_ptr)
QScopedPointer< QOpenGLVertexArrayObject > vao
bool buildProgram(ProgramIndex idx, const char *vs, const char *fs)
void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform)
bool prepareProgram(const QMatrix4x4 &vertexTransform)
Combined button and popup list for selecting options.
#define GL_TEXTURE_EXTERNAL_OES
#define GL_TEXTURE_RECTANGLE
#define GL_TEXTURE_WIDTH
static const char fragment_shader_external_oes[]
static const char fragment_shader150[]
static const char vertex_shader[]
#define GL_TEXTURE_HEIGHT
static const GLfloat texture_buffer_data[]
static const char fragment_shader150_rectangle[]
static const GLfloat vertex_buffer_data[]
static const char fragment_shader_rectangle[]
static QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GLenum target)
static const char fragment_shader[]
static const char vertex_shader150[]
QScopedPointer< QOpenGLShaderProgram > glProgram