aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorAndy Nichols <andy.nichols@qt.io>2016-11-29 15:29:39 +0100
committerAndy Nichols <andy.nichols@qt.io>2016-12-13 15:43:24 +0000
commit0119439c9d25dfd892bbee47068e9d726f4bff97 (patch)
tree71df5718b21cd1471eb6cb4c4eac4c19a691f869 /src/plugins
parent3f57f2b7cc3899af154257a3c858bd23d9f03a62 (diff)
OpenVG: Support rendering paths with non-affine transforms
The current approach to rendering paths (used by Rectangles and Glyph nodes) does not support rendering with non-affine transformations. That is because OpenVG does not support passing a non-affine transformation matrix when rendering paths. So instead when using a non-affine transform we will fallback to rendering to an offscreen VGImage, then rendering that as an image which can have a perspective transform. Change-Id: I01508bcb67b339323cb6400c7ff6d885b62c5e02 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/scenegraph/openvg/openvg.pro6
-rw-r--r--src/plugins/scenegraph/openvg/qopenvgmatrix.cpp53
-rw-r--r--src/plugins/scenegraph/openvg/qopenvgmatrix.h9
-rw-r--r--src/plugins/scenegraph/openvg/qopenvgoffscreensurface.cpp113
-rw-r--r--src/plugins/scenegraph/openvg/qopenvgoffscreensurface.h73
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp23
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.cpp3
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp207
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h4
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvglayer.cpp126
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvglayer.h7
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp60
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h14
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgpainternode.cpp4
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.cpp59
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.h2
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgrenderable.cpp10
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgrenderable.h6
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp4
19 files changed, 586 insertions, 197 deletions
diff --git a/src/plugins/scenegraph/openvg/openvg.pro b/src/plugins/scenegraph/openvg/openvg.pro
index fb9b3b93f5..8a58796a05 100644
--- a/src/plugins/scenegraph/openvg/openvg.pro
+++ b/src/plugins/scenegraph/openvg/openvg.pro
@@ -31,7 +31,8 @@ HEADERS += \
qsgopenvgfontglyphcache.h \
qsgopenvgpainternode.h \
qsgopenvgspritenode.h \
- qsgopenvgrenderable.h
+ qsgopenvgrenderable.h \
+ qopenvgoffscreensurface.h
SOURCES += \
qsgopenvgadaptation.cpp \
@@ -51,4 +52,5 @@ SOURCES += \
qsgopenvgfontglyphcache.cpp \
qsgopenvgpainternode.cpp \
qsgopenvgspritenode.cpp \
- qsgopenvgrenderable.cpp
+ qsgopenvgrenderable.cpp \
+ qopenvgoffscreensurface.cpp
diff --git a/src/plugins/scenegraph/openvg/qopenvgmatrix.cpp b/src/plugins/scenegraph/openvg/qopenvgmatrix.cpp
index e55de2ce0d..83ce96578e 100644
--- a/src/plugins/scenegraph/openvg/qopenvgmatrix.cpp
+++ b/src/plugins/scenegraph/openvg/qopenvgmatrix.cpp
@@ -97,6 +97,19 @@ void QOpenVGMatrix::setToIdentity()
m[2][2] = 1.0f;
}
+bool QOpenVGMatrix::isAffine() const
+{
+ if (m[0][2] == 0.0f && m[1][2] == 0.0f && m[2][2] == 1.0f)
+ return true;
+
+ return false;
+}
+
+QPointF QOpenVGMatrix::map(const QPointF &point) const
+{
+ return *this * point;
+}
+
void QOpenVGMatrix::fill(float value)
{
m[0][0] = value;
@@ -287,6 +300,46 @@ QOpenVGMatrix operator*(const QOpenVGMatrix &m1, const QOpenVGMatrix &m2)
return matrix;
}
+QPointF operator*(const QPointF& point, const QOpenVGMatrix& matrix)
+{
+ float xin = point.x();
+ float yin = point.y();
+ float x = xin * matrix.m[0][0] +
+ yin * matrix.m[0][1] +
+ matrix.m[0][2];
+ float y = xin * matrix.m[1][0] +
+ yin * matrix.m[1][1] +
+ matrix.m[1][2];
+ float w = xin * matrix.m[2][0] +
+ yin * matrix.m[2][1] +
+ matrix.m[2][2];
+ if (w == 1.0f) {
+ return QPointF(float(x), float(y));
+ } else {
+ return QPointF(float(x / w), float(y / w));
+ }
+}
+
+QPointF operator*(const QOpenVGMatrix& matrix, const QPointF& point)
+{
+ float xin = point.x();
+ float yin = point.y();
+ float x = xin * matrix.m[0][0] +
+ yin * matrix.m[1][0] +
+ matrix.m[2][0];
+ float y = xin * matrix.m[0][1] +
+ yin * matrix.m[1][1] +
+ matrix.m[2][1];
+ float w = xin * matrix.m[0][2] +
+ yin * matrix.m[1][2] +
+ matrix.m[2][2];
+ if (w == 1.0f) {
+ return QPointF(float(x), float(y));
+ } else {
+ return QPointF(float(x / w), float(y / w));
+ }
+}
+
QDebug operator<<(QDebug dbg, const QOpenVGMatrix &m)
{
QDebugStateSaver saver(dbg);
diff --git a/src/plugins/scenegraph/openvg/qopenvgmatrix.h b/src/plugins/scenegraph/openvg/qopenvgmatrix.h
index 644c9da5bc..f51bf8147d 100644
--- a/src/plugins/scenegraph/openvg/qopenvgmatrix.h
+++ b/src/plugins/scenegraph/openvg/qopenvgmatrix.h
@@ -42,6 +42,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/QDataStream>
+#include <QtCore/QPointF>
QT_BEGIN_NAMESPACE
@@ -57,6 +58,10 @@ public:
bool isIdentity() const;
void setToIdentity();
+ bool isAffine() const;
+
+ QPointF map(const QPointF& point) const;
+
void fill(float value);
QOpenVGMatrix transposed() const;
@@ -67,6 +72,8 @@ public:
QOpenVGMatrix& operator*=(float factor);
QOpenVGMatrix& operator/=(float divisor);
friend QOpenVGMatrix operator*(const QOpenVGMatrix& m1, const QOpenVGMatrix& m2);
+ friend QPointF operator*(const QPointF& point, const QOpenVGMatrix& matrix);
+ friend QPointF operator*(const QOpenVGMatrix& matrix, const QPointF& point);
#ifndef QT_NO_DEBUG_STREAM
friend QDebug operator<<(QDebug dbg, const QOpenVGMatrix &m);
#endif
@@ -84,6 +91,8 @@ private:
};
QOpenVGMatrix operator*(const QOpenVGMatrix& m1, const QOpenVGMatrix& m2);
+QPointF operator*(const QPointF& point, const QOpenVGMatrix& matrix);
+QPointF operator*(const QOpenVGMatrix& matrix, const QPointF& point);
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QOpenVGMatrix &m);
diff --git a/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.cpp b/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.cpp
new file mode 100644
index 0000000000..3a4643ab5a
--- /dev/null
+++ b/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopenvgoffscreensurface.h"
+
+QT_BEGIN_NAMESPACE
+
+QOpenVGOffscreenSurface::QOpenVGOffscreenSurface(const QSize &size)
+ : m_size(size)
+{
+ m_display = eglGetCurrentDisplay();
+ m_image = vgCreateImage(VG_sARGB_8888_PRE, m_size.width(), m_size.height(), VG_IMAGE_QUALITY_BETTER);
+
+ const EGLint configAttribs[] = {
+ EGL_CONFORMANT, EGL_OPENVG_BIT,
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_ALPHA_MASK_SIZE, 8,
+ EGL_NONE
+ };
+
+ EGLConfig pbufferConfig;
+ EGLint numConfig;
+ eglChooseConfig(m_display, configAttribs, &pbufferConfig, 1, &numConfig);
+
+ m_context = eglCreateContext(m_display, pbufferConfig, eglGetCurrentContext(), 0);
+ if (m_context == EGL_NO_CONTEXT)
+ qWarning("QOpenVGOffscreenSurface: failed to create EGLContext");
+
+ m_renderTarget = eglCreatePbufferFromClientBuffer(m_display,
+ EGL_OPENVG_IMAGE,
+ (EGLClientBuffer)m_image,
+ pbufferConfig,
+ 0);
+ if (m_renderTarget == EGL_NO_SURFACE)
+ qWarning("QOpenVGOffscreenSurface: failed to create EGLSurface from VGImage");
+}
+
+QOpenVGOffscreenSurface::~QOpenVGOffscreenSurface()
+{
+ vgDestroyImage(m_image);
+ eglDestroySurface(m_display, m_renderTarget);
+}
+
+void QOpenVGOffscreenSurface::makeCurrent()
+{
+ EGLContext currentContext = eglGetCurrentContext();
+ if (m_context != currentContext) {
+ m_previousContext = eglGetCurrentContext();
+ m_previousReadSurface = eglGetCurrentSurface(EGL_READ);
+ m_previousDrawSurface = eglGetCurrentSurface(EGL_DRAW);
+
+ eglMakeCurrent(m_display, m_renderTarget, m_renderTarget, m_context);
+ }
+}
+
+void QOpenVGOffscreenSurface::doneCurrent()
+{
+ EGLContext currentContext = eglGetCurrentContext();
+ if (m_context == currentContext) {
+ eglMakeCurrent(m_display, m_previousDrawSurface, m_previousReadSurface, m_previousContext);
+ m_context = EGL_NO_CONTEXT;
+ m_previousContext = EGL_NO_CONTEXT;
+ m_previousReadSurface = EGL_NO_SURFACE;
+ m_previousDrawSurface = EGL_NO_SURFACE;
+ }
+}
+
+void QOpenVGOffscreenSurface::swapBuffers()
+{
+ eglSwapBuffers(m_display, m_renderTarget);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.h b/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.h
new file mode 100644
index 0000000000..833c9669bf
--- /dev/null
+++ b/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPENVGOFFSCREENSURFACE_H
+#define QOPENVGOFFSCREENSURFACE_H
+
+#include "qopenvgcontext_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QOpenVGOffscreenSurface
+{
+public:
+ QOpenVGOffscreenSurface(const QSize &size);
+ ~QOpenVGOffscreenSurface();
+
+ void makeCurrent();
+ void doneCurrent();
+ void swapBuffers();
+
+ VGImage image() { return m_image; }
+ QSize size() const { return m_size; }
+
+private:
+ VGImage m_image;
+ QSize m_size;
+ EGLContext m_context;
+ EGLSurface m_renderTarget;
+ EGLContext m_previousContext = EGL_NO_CONTEXT;
+ EGLSurface m_previousReadSurface = EGL_NO_SURFACE;
+ EGLSurface m_previousDrawSurface = EGL_NO_SURFACE;
+ EGLDisplay m_display;
+};
+
+QT_END_NAMESPACE
+
+#endif // QOPENVGOFFSCREENSURFACE_H
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp b/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp
index c90f0f0bbe..8be2a97034 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp
@@ -42,6 +42,7 @@
#include "qsgopenvgcontext_p.h"
#include "qsgopenvghelpers.h"
#include "qsgopenvgfontglyphcache.h"
+#include "qopenvgoffscreensurface.h"
QT_BEGIN_NAMESPACE
@@ -82,6 +83,7 @@ void QSGOpenVGGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &gly
m_position = position;
m_glyphRun = glyphs;
+ m_bounding_rect = glyphs.boundingRect().translated(m_position - QPointF(0.0, glyphs.rawFont().ascent()));
// Recreate ajustments
m_xAdjustments.clear();
@@ -133,8 +135,22 @@ void QSGOpenVGGlyphNode::render()
// Rendering Style
qreal offset = 1.0;
+ QOpenVGOffscreenSurface *offscreenSurface = nullptr;
+
+ // Set Transform
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
+ if (transform().isAffine()) {
+ vgLoadMatrix(transform().constData());
+ } else {
+ vgLoadIdentity();
+ offscreenSurface = new QOpenVGOffscreenSurface(QSize(ceil(m_bounding_rect.width()), ceil(m_bounding_rect.height())));
+ offscreenSurface->makeCurrent();
+ }
+
+ // Set Quality
vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_BETTER);
+
switch (m_style) {
case QQuickText::Normal: break;
case QQuickText::Outline:
@@ -159,6 +175,13 @@ void QSGOpenVGGlyphNode::render()
vgSetPaint(m_fontColorPaint, VG_FILL_PATH);
drawGlyphsAtOffset(QPointF(0.0, 0.0));
+ if (!transform().isAffine()) {
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(transform().constData());
+ offscreenSurface->doneCurrent();
+ vgDrawImage(offscreenSurface->image());
+ delete offscreenSurface;
+ }
}
void QSGOpenVGGlyphNode::setOpacity(float opacity)
diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.cpp
index 2ab477f116..c9545d5e9a 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.cpp
@@ -72,6 +72,9 @@ void QSGOpenVGInternalImageNode::render()
vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
}
+ // Set Transform
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(transform().constData());
VGImage image = static_cast<VGImage>(m_texture->textureId());
QSize textureSize = m_texture->textureSize();
diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
index 372dffbbc2..be437303bc 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
@@ -193,6 +193,33 @@ void QSGOpenVGInternalRectangleNode::update()
void QSGOpenVGInternalRectangleNode::render()
{
+ // Set Transform
+ if (transform().isAffine()) {
+ // Use current transform matrix
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+ vgLoadMatrix(transform().constData());
+ if (m_offscreenSurface) {
+ delete m_offscreenSurface;
+ m_offscreenSurface = nullptr;
+ }
+ } else {
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+ vgLoadIdentity();
+ if (m_radius > 0) {
+ // Fallback to rendering to an image for rounded rects with perspective transforms
+ if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != QSize(ceil(m_rect.width()), ceil(m_rect.height()))) {
+ delete m_offscreenSurface;
+ m_offscreenSurface = new QOpenVGOffscreenSurface(QSize(ceil(m_rect.width()), ceil(m_rect.height())));
+ }
+
+ m_offscreenSurface->makeCurrent();
+ } else if (m_offscreenSurface) {
+ delete m_offscreenSurface;
+ m_offscreenSurface = nullptr;
+ }
+ }
+
+
// If path is dirty
if (m_pathDirty) {
vgClearPath(m_rectanglePath, VG_PATH_CAPABILITY_APPEND_TO);
@@ -257,6 +284,14 @@ void QSGOpenVGInternalRectangleNode::render()
vgSetPaint(m_rectanglePaint, VG_FILL_PATH);
vgDrawPath(m_rectanglePath, VG_FILL_PATH);
}
+
+ if (!transform().isAffine() && m_radius > 0) {
+ m_offscreenSurface->doneCurrent();
+ // Render offscreen surface
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(transform().constData());
+ vgDrawImage(m_offscreenSurface->image());
+ }
}
void QSGOpenVGInternalRectangleNode::setOpacity(float opacity)
@@ -268,6 +303,15 @@ void QSGOpenVGInternalRectangleNode::setOpacity(float opacity)
}
}
+void QSGOpenVGInternalRectangleNode::setTransform(const QOpenVGMatrix &transform)
+{
+ // if there transform matrix is not affine, regenerate the path
+ if (transform.isAffine())
+ m_pathDirty = true;
+
+ QSGOpenVGRenderable::setTransform(transform);
+}
+
void QSGOpenVGInternalRectangleNode::createVGResources()
{
m_rectanglePaint = vgCreatePaint();
@@ -280,6 +324,9 @@ void QSGOpenVGInternalRectangleNode::createVGResources()
void QSGOpenVGInternalRectangleNode::destroyVGResources()
{
+ if (m_offscreenSurface)
+ delete m_offscreenSurface;
+
vgDestroyPaint(m_rectanglePaint);
vgDestroyPaint(m_borderPaint);
vgDestroyPath(m_rectanglePath);
@@ -290,25 +337,50 @@ void QSGOpenVGInternalRectangleNode::generateRectanglePath(const QRectF &rect, f
{
if (radius == 0) {
// Generate a rectangle
+ if (transform().isAffine()) {
+ // Create command list
+ static const VGubyte rectCommands[] = {
+ VG_MOVE_TO_ABS,
+ VG_HLINE_TO_REL,
+ VG_VLINE_TO_REL,
+ VG_HLINE_TO_REL,
+ VG_CLOSE_PATH
+ };
- // Create command list
- static const VGubyte rectCommands[] = {
- VG_MOVE_TO_ABS,
- VG_HLINE_TO_REL,
- VG_VLINE_TO_REL,
- VG_HLINE_TO_REL,
- VG_CLOSE_PATH
- };
+ // Create command data
+ QVector<VGfloat> coordinates(5);
+ coordinates[0] = rect.x();
+ coordinates[1] = rect.y();
+ coordinates[2] = rect.width();
+ coordinates[3] = rect.height();
+ coordinates[4] = -rect.width();
+ vgAppendPathData(path, 5, rectCommands, coordinates.constData());
+ } else {
+ // Pre-transform path
+ static const VGubyte rectCommands[] = {
+ VG_MOVE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_CLOSE_PATH
+ };
- // Create command data
- QVector<VGfloat> coordinates(5);
- coordinates[0] = rect.x();
- coordinates[1] = rect.y();
- coordinates[2] = rect.width();
- coordinates[3] = rect.height();
- coordinates[4] = -rect.width();
-
- vgAppendPathData(path, 5, rectCommands, coordinates.constData());
+ QVector<VGfloat> coordinates(8);
+ const QPointF topLeft = transform().map(rect.topLeft());
+ const QPointF topRight = transform().map(rect.topRight());
+ const QPointF bottomLeft = transform().map(rect.bottomLeft());
+ const QPointF bottomRight = transform().map(rect.bottomRight());
+ coordinates[0] = bottomLeft.x();
+ coordinates[1] = bottomLeft.y();
+ coordinates[2] = bottomRight.x();
+ coordinates[3] = bottomRight.y();
+ coordinates[4] = topRight.x();
+ coordinates[5] = topRight.y();
+ coordinates[6] = topLeft.x();
+ coordinates[7] = topLeft.y();
+
+ vgAppendPathData(path, 5, rectCommands, coordinates.constData());
+ }
} else {
// Generate a rounded rectangle
//Radius should never exceeds half of the width or half of the height
@@ -377,35 +449,82 @@ void QSGOpenVGInternalRectangleNode::generateBorderPath(const QRectF &rect, floa
{
if (radius == 0) {
// squared frame
- // Create command list
- static const VGubyte squaredBorderCommands[] = {
- VG_MOVE_TO_ABS,
- VG_HLINE_TO_REL,
- VG_VLINE_TO_REL,
- VG_HLINE_TO_REL,
- VG_MOVE_TO_ABS,
- VG_VLINE_TO_REL,
- VG_HLINE_TO_REL,
- VG_VLINE_TO_REL,
- VG_CLOSE_PATH
- };
+ if (transform().isAffine()) {
+ // Create command list
+ static const VGubyte squaredBorderCommands[] = {
+ VG_MOVE_TO_ABS,
+ VG_HLINE_TO_REL,
+ VG_VLINE_TO_REL,
+ VG_HLINE_TO_REL,
+ VG_MOVE_TO_ABS,
+ VG_VLINE_TO_REL,
+ VG_HLINE_TO_REL,
+ VG_VLINE_TO_REL,
+ VG_CLOSE_PATH
+ };
- // Create command data
- QVector<VGfloat> coordinates(10);
- // Outside Square
- coordinates[0] = rect.x();
- coordinates[1] = rect.y();
- coordinates[2] = rect.width();
- coordinates[3] = rect.height();
- coordinates[4] = -rect.width();
- // Inside Square (opposite direction)
- coordinates[5] = rect.x() + borderWidth;
- coordinates[6] = rect.y() + borderHeight;
- coordinates[7] = rect.height() - (borderHeight * 2);
- coordinates[8] = rect.width() - (borderWidth * 2);
- coordinates[9] = -(rect.height() - (borderHeight * 2));
+ // Create command data
+ QVector<VGfloat> coordinates(10);
+ // Outside Square
+ coordinates[0] = rect.x();
+ coordinates[1] = rect.y();
+ coordinates[2] = rect.width();
+ coordinates[3] = rect.height();
+ coordinates[4] = -rect.width();
+ // Inside Square (opposite direction)
+ coordinates[5] = rect.x() + borderWidth;
+ coordinates[6] = rect.y() + borderHeight;
+ coordinates[7] = rect.height() - (borderHeight * 2);
+ coordinates[8] = rect.width() - (borderWidth * 2);
+ coordinates[9] = -(rect.height() - (borderHeight * 2));
+
+ vgAppendPathData(path, 9, squaredBorderCommands, coordinates.constData());
+ } else {
+ // persepective transform
+ static const VGubyte squaredBorderCommands[] = {
+ VG_MOVE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_MOVE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_CLOSE_PATH
+ };
- vgAppendPathData(path, 9, squaredBorderCommands, coordinates.constData());
+ QVector<VGfloat> coordinates(16);
+ QRectF insideRect = rect.marginsRemoved(QMarginsF(borderWidth, borderHeight, borderWidth, borderHeight));
+ QPointF outsideBottomLeft = transform().map(rect.bottomLeft());
+ QPointF outsideBottomRight = transform().map(rect.bottomRight());
+ QPointF outsideTopRight = transform().map(rect.topRight());
+ QPointF outsideTopLeft = transform().map(rect.topLeft());
+ QPointF insideBottomLeft = transform().map(insideRect.bottomLeft());
+ QPointF insideTopLeft = transform().map(insideRect.topLeft());
+ QPointF insideTopRight = transform().map(insideRect.topRight());
+ QPointF insideBottomRight = transform().map(insideRect.bottomRight());
+
+ // Outside
+ coordinates[0] = outsideBottomLeft.x();
+ coordinates[1] = outsideBottomLeft.y();
+ coordinates[2] = outsideBottomRight.x();
+ coordinates[3] = outsideBottomRight.y();
+ coordinates[4] = outsideTopRight.x();
+ coordinates[5] = outsideTopRight.y();
+ coordinates[6] = outsideTopLeft.x();
+ coordinates[7] = outsideTopLeft.y();
+ // Inside
+ coordinates[8] = insideBottomLeft.x();
+ coordinates[9] = insideBottomLeft.y();
+ coordinates[10] = insideTopLeft.x();
+ coordinates[11] = insideTopLeft.y();
+ coordinates[12] = insideTopRight.x();
+ coordinates[13] = insideTopRight.y();
+ coordinates[14] = insideBottomRight.x();
+ coordinates[15] = insideBottomRight.y();
+
+ vgAppendPathData(path, 9, squaredBorderCommands, coordinates.constData());
+ }
} else if (radius < qMax(borderWidth, borderHeight)){
// rounded outside, squared inside
// Create command list
diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h
index 0d5283773f..e8d25c94f8 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h
@@ -42,6 +42,7 @@
#include <private/qsgadaptationlayer_p.h>
#include "qsgopenvgrenderable.h"
+#include "qopenvgoffscreensurface.h"
#include <VG/openvg.h>
@@ -64,6 +65,7 @@ public:
void render() override;
void setOpacity(float opacity) override;
+ void setTransform(const QOpenVGMatrix &transform) override;
private:
void createVGResources();
@@ -89,6 +91,8 @@ private:
VGPath m_borderPath;
VGPaint m_rectanglePaint;
VGPaint m_borderPaint;
+
+ QOpenVGOffscreenSurface *m_offscreenSurface = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/openvg/qsgopenvglayer.cpp b/src/plugins/scenegraph/openvg/qsgopenvglayer.cpp
index 03a82ca4ee..cafd0d4e1e 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvglayer.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvglayer.cpp
@@ -53,12 +53,9 @@ QSGOpenVGLayer::QSGOpenVGLayer(QSGRenderContext *renderContext)
, m_grab(true)
, m_recursive(false)
, m_dirtyTexture(true)
- , m_image(0)
- , m_renderTarget(0)
- , m_layerContext(0)
+ , m_offscreenSurface(nullptr)
{
m_context = static_cast<QSGOpenVGRenderContext*>(renderContext);
- m_vgContext = m_context->vgContext();
}
QSGOpenVGLayer::~QSGOpenVGLayer()
@@ -68,15 +65,16 @@ QSGOpenVGLayer::~QSGOpenVGLayer()
int QSGOpenVGLayer::textureId() const
{
- return static_cast<int>(m_image);
+ if (m_offscreenSurface)
+ return static_cast<int>(m_offscreenSurface->image());
+ else
+ return 0;
}
QSize QSGOpenVGLayer::textureSize() const
{
- if (m_image != 0) {
- VGint imageWidth = vgGetParameteri(m_image, VG_IMAGE_WIDTH);
- VGint imageHeight = vgGetParameteri(m_image, VG_IMAGE_HEIGHT);
- return QSize(imageWidth, imageHeight);
+ if (m_offscreenSurface) {
+ return m_offscreenSurface->size();
}
return QSize();
@@ -84,42 +82,7 @@ QSize QSGOpenVGLayer::textureSize() const
bool QSGOpenVGLayer::hasAlphaChannel() const
{
- VGImageFormat format = static_cast<VGImageFormat>(vgGetParameteri(m_image, VG_IMAGE_FORMAT));
-
- switch (format) {
- case VG_sRGBA_8888:
- case VG_sRGBA_8888_PRE:
- case VG_sRGBA_5551:
- case VG_sRGBA_4444:
- case VG_lRGBA_8888:
- case VG_lRGBA_8888_PRE:
- case VG_A_8:
- case VG_A_1:
- case VG_A_4:
- case VG_sARGB_8888:
- case VG_sARGB_8888_PRE:
- case VG_sARGB_1555:
- case VG_sARGB_4444:
- case VG_lARGB_8888:
- case VG_lARGB_8888_PRE:
- case VG_sBGRA_8888:
- case VG_sBGRA_8888_PRE:
- case VG_sBGRA_5551:
- case VG_sBGRA_4444:
- case VG_lBGRA_8888:
- case VG_lBGRA_8888_PRE:
- case VG_sABGR_8888:
- case VG_sABGR_8888_PRE:
- case VG_sABGR_1555:
- case VG_sABGR_4444:
- case VG_lABGR_8888:
- case VG_lABGR_8888_PRE:
- return true;
- break;
- default:
- break;
- }
- return false;
+ return true;
}
bool QSGOpenVGLayer::hasMipmaps() const
@@ -149,8 +112,8 @@ void QSGOpenVGLayer::setItem(QSGNode *item)
m_item = item;
if (m_live && !m_item) {
- vgDestroyImage(m_image);
- m_image = 0;
+ delete m_offscreenSurface;
+ m_offscreenSurface = nullptr;
}
markDirtyTexture();
@@ -171,8 +134,8 @@ void QSGOpenVGLayer::setSize(const QSize &size)
m_size = size;
if (m_live && m_size.isNull()) {
- vgDestroyImage(m_image);
- m_image = 0;
+ delete m_offscreenSurface;
+ m_offscreenSurface = nullptr;
}
markDirtyTexture();
@@ -201,8 +164,8 @@ void QSGOpenVGLayer::setLive(bool live)
m_live = live;
if (m_live && (!m_item || m_size.isNull())) {
- vgDestroyImage(m_image);
- m_image = 0;
+ delete m_offscreenSurface;
+ m_offscreenSurface = nullptr;
}
markDirtyTexture();
@@ -254,15 +217,17 @@ void QSGOpenVGLayer::markDirtyTexture()
void QSGOpenVGLayer::invalidated()
{
+ delete m_offscreenSurface;
delete m_renderer;
- m_renderer = 0;
+ m_renderer = nullptr;
+ m_offscreenSurface = nullptr;
}
void QSGOpenVGLayer::grab()
{
if (!m_item || m_size.isNull()) {
- vgDestroyImage(m_image);
- m_image = 0;
+ delete m_offscreenSurface;
+ m_offscreenSurface = nullptr;
m_dirtyTexture = false;
return;
}
@@ -279,47 +244,12 @@ void QSGOpenVGLayer::grab()
m_renderer->setDevicePixelRatio(m_device_pixel_ratio);
m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
- if (m_image == 0 || m_imageSize != m_size ) {
- if (m_image != 0)
- vgDestroyImage(m_image);
-
- m_image = vgCreateImage(VG_lARGB_8888_PRE, m_size.width(), m_size.height(), VG_IMAGE_QUALITY_BETTER);
- m_imageSize = m_size;
-
- //Destroy old RenderTarget
- if (m_renderTarget != 0)
- eglDestroySurface(m_vgContext->eglDisplay(), m_renderTarget);
-
- const EGLint configAttribs[] = {
- EGL_CONFORMANT, EGL_OPENVG_BIT,
- EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
- EGL_ALPHA_MASK_SIZE, 8,
- EGL_NONE
- };
-
- EGLConfig pbufferConfig;
- EGLint numConfig;
- eglChooseConfig(m_vgContext->eglDisplay(), configAttribs, &pbufferConfig, 1, &numConfig);
-
- if (m_layerContext == 0) {
- // Create new context
- m_layerContext = eglCreateContext(m_vgContext->eglDisplay(), pbufferConfig, m_vgContext->eglContext(), 0);
- }
-
- m_renderTarget = eglCreatePbufferFromClientBuffer(m_vgContext->eglDisplay(),
- EGL_OPENVG_IMAGE,
- (EGLClientBuffer)m_image,
- pbufferConfig,
- 0);
- }
- if (m_renderTarget == EGL_NO_SURFACE) {
- qDebug() << "invalid renderTarget!";
- return;
+ if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != m_size ) {
+ if (m_offscreenSurface != nullptr)
+ delete m_offscreenSurface;
+
+ m_offscreenSurface = new QOpenVGOffscreenSurface(m_size);
}
// Render texture.
@@ -337,7 +267,7 @@ void QSGOpenVGLayer::grab()
m_renderer->setProjectionMatrixToRect(mirrored);
m_renderer->setClearColor(Qt::transparent);
- eglMakeCurrent(m_vgContext->eglDisplay(), m_renderTarget, m_renderTarget, m_layerContext);
+ m_offscreenSurface->makeCurrent();
// Before Rendering setup context for adjusting to Qt Coordinates to PixelBuffer
// Should already be inverted by default
@@ -346,10 +276,8 @@ void QSGOpenVGLayer::grab()
m_renderer->renderScene();
- eglSwapBuffers(m_vgContext->eglDisplay(), m_renderTarget);
-
- // make the default surface current again
- m_vgContext->makeCurrent();
+ // Make the previous surface and context active again
+ m_offscreenSurface->doneCurrent();
root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update.
diff --git a/src/plugins/scenegraph/openvg/qsgopenvglayer.h b/src/plugins/scenegraph/openvg/qsgopenvglayer.h
index ee9984b9d9..760a22f0bc 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvglayer.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvglayer.h
@@ -44,6 +44,7 @@
#include <private/qsgcontext_p.h>
#include "qopenvgcontext_p.h"
+#include "qopenvgoffscreensurface.h"
QT_BEGIN_NAMESPACE
@@ -103,11 +104,7 @@ private:
bool m_recursive;
bool m_dirtyTexture;
- QOpenVGContext *m_vgContext;
- VGImage m_image;
- QSize m_imageSize;
- EGLSurface m_renderTarget;
- EGLContext m_layerContext;
+ QOpenVGOffscreenSurface *m_offscreenSurface;
};
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp
index fc9f5eb57c..8aa179f705 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp
@@ -93,12 +93,11 @@ bool QSGOpenVGNodeVisitor::visit(QSGClipNode *node)
// Render clip node geometry to mask
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
- vgLoadMatrix(m_transformStack.top().constData());
+ vgLoadIdentity();
VGPath clipPath = generateClipPath(node->clipRect());
vgRenderToMask(clipPath, VG_FILL_PATH, maskOperation);
- auto clipState = new ClipState(clipPath, m_transformStack.top());
- m_clipStack.push(clipState);
+ m_clipStack.push(clipPath);
return true;
}
@@ -107,29 +106,23 @@ void QSGOpenVGNodeVisitor::endVisit(QSGClipNode *)
{
// Remove clip node geometry from mask
auto clipState = m_clipStack.pop();
- vgDestroyPath(clipState->path);
+ vgDestroyPath(clipState);
if (m_clipStack.count() == 0) {
vgSeti(VG_MASKING, VG_FALSE);
} else {
// Recreate the mask
vgMask(0,VG_FILL_MASK, 0, 0, VG_MAXINT, VG_MAXINT);
- for (auto state : m_clipStack) {
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
- vgLoadMatrix(state->transform.constData());
- vgRenderToMask(state->path, VG_FILL_PATH, VG_INTERSECT_MASK);
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+ vgLoadIdentity();
+ for (auto path : qAsConst(m_clipStack)) {
+ vgRenderToMask(path, VG_FILL_PATH, VG_INTERSECT_MASK);
}
}
-
- delete clipState;
}
bool QSGOpenVGNodeVisitor::visit(QSGGeometryNode *node)
{
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
- vgLoadMatrix(m_transformStack.top().constData());
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
- vgLoadMatrix(m_transformStack.top().constData());
if (QSGSimpleRectNode *rectNode = dynamic_cast<QSGSimpleRectNode *>(node)) {
// TODO: Try and render the QSGSimpleRectNode
Q_UNUSED(rectNode)
@@ -169,8 +162,6 @@ void QSGOpenVGNodeVisitor::endVisit(QSGOpacityNode *)
bool QSGOpenVGNodeVisitor::visit(QSGInternalImageNode *node)
{
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
- vgLoadMatrix(m_transformStack.top().constData());
renderRenderableNode(static_cast<QSGOpenVGInternalImageNode*>(node));
return true;
}
@@ -181,8 +172,6 @@ void QSGOpenVGNodeVisitor::endVisit(QSGInternalImageNode *)
bool QSGOpenVGNodeVisitor::visit(QSGPainterNode *node)
{
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
- vgLoadMatrix(m_transformStack.top().constData());
renderRenderableNode(static_cast<QSGOpenVGPainterNode*>(node));
return true;
}
@@ -193,8 +182,6 @@ void QSGOpenVGNodeVisitor::endVisit(QSGPainterNode *)
bool QSGOpenVGNodeVisitor::visit(QSGInternalRectangleNode *node)
{
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
- vgLoadMatrix(m_transformStack.top().constData());
renderRenderableNode(static_cast<QSGOpenVGInternalRectangleNode*>(node));
return true;
}
@@ -205,8 +192,6 @@ void QSGOpenVGNodeVisitor::endVisit(QSGInternalRectangleNode *)
bool QSGOpenVGNodeVisitor::visit(QSGGlyphNode *node)
{
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE);
- vgLoadMatrix(m_transformStack.top().constData());
renderRenderableNode(static_cast<QSGOpenVGGlyphNode*>(node));
return true;
}
@@ -226,8 +211,6 @@ void QSGOpenVGNodeVisitor::endVisit(QSGRootNode *)
bool QSGOpenVGNodeVisitor::visit(QSGSpriteNode *node)
{
- vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
- vgLoadMatrix(m_transformStack.top().constData());
renderRenderableNode(static_cast<QSGOpenVGSpriteNode*>(node));
return true;
}
@@ -253,19 +236,28 @@ VGPath QSGOpenVGNodeVisitor::generateClipPath(const QRectF &rect) const
// Create command list
static const VGubyte rectCommands[] = {
VG_MOVE_TO_ABS,
- VG_HLINE_TO_REL,
- VG_VLINE_TO_REL,
- VG_HLINE_TO_REL,
+ VG_LINE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_LINE_TO_ABS,
VG_CLOSE_PATH
};
+ const QOpenVGMatrix &transform = m_transformStack.top();
+
// Create command data
- QVector<VGfloat> coordinates(5);
- coordinates[0] = rect.x();
- coordinates[1] = rect.y();
- coordinates[2] = rect.width();
- coordinates[3] = rect.height();
- coordinates[4] = -rect.width();
+ QVector<VGfloat> coordinates(8);
+ const QPointF topLeft = transform.map(rect.topLeft());
+ const QPointF topRight = transform.map(rect.topRight());
+ const QPointF bottomLeft = transform.map(rect.bottomLeft());
+ const QPointF bottomRight = transform.map(rect.bottomRight());
+ coordinates[0] = bottomLeft.x();
+ coordinates[1] = bottomLeft.y();
+ coordinates[2] = bottomRight.x();
+ coordinates[3] = bottomRight.y();
+ coordinates[4] = topRight.x();
+ coordinates[5] = topRight.y();
+ coordinates[6] = topLeft.x();
+ coordinates[7] = topLeft.y();
vgAppendPathData(clipPath, 5, rectCommands, coordinates.constData());
return clipPath;
@@ -275,7 +267,7 @@ void QSGOpenVGNodeVisitor::renderRenderableNode(QSGOpenVGRenderable *node)
{
if (!node)
return;
-
+ node->setTransform(m_transformStack.top());
node->setOpacity(m_opacityState.top());
node->render();
}
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h
index 3105f2076d..4805d63024 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h
@@ -79,24 +79,12 @@ public:
void endVisit(QSGRenderNode *) override;
private:
- struct ClipState {
- ClipState(VGPath p, QOpenVGMatrix t)
- {
- path = p;
- transform = t;
- }
-
- VGPath path;
- QOpenVGMatrix transform;
- };
-
VGPath generateClipPath(const QRectF &rect) const;
void renderRenderableNode(QSGOpenVGRenderable *node);
-
QStack<QOpenVGMatrix> m_transformStack;
QStack<float> m_opacityState;
- QStack<ClipState*> m_clipStack;
+ QStack<VGPath> m_clipStack;
};
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgpainternode.cpp b/src/plugins/scenegraph/openvg/qsgopenvgpainternode.cpp
index c09ca6a47e..fb68ebf2bc 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgpainternode.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgpainternode.cpp
@@ -193,6 +193,10 @@ void QSGOpenVGPainterNode::render()
else
vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_NONANTIALIASED);
+ // Set Transform
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(transform().constData());
+
vgDrawImage(static_cast<VGImage>(m_texture->textureId()));
}
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.cpp b/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.cpp
index f5890210a9..1afc5ea7ca 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.cpp
@@ -73,10 +73,33 @@ void QSGOpenVGRectangleNode::setColor(const QColor &color)
markDirty(DirtyMaterial);
}
+void QSGOpenVGRectangleNode::setTransform(const QOpenVGMatrix &transform)
+{
+ // if there transform matrix is not affine, regenerate the path
+ if (transform.isAffine())
+ m_pathDirty = true;
+ markDirty(DirtyGeometry);
+
+ QSGOpenVGRenderable::setTransform(transform);
+}
+
void QSGOpenVGRectangleNode::render()
{
+ // Set Transform
+ if (transform().isAffine()) {
+ // Use current transform matrix
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+ vgLoadMatrix(transform().constData());
+ } else {
+ // map the path's to handle the perspective matrix
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
+ vgLoadIdentity();
+ }
+
if (m_pathDirty) {
vgClearPath(m_rectPath, VG_PATH_CAPABILITY_APPEND_TO);
+
+ if (transform().isAffine()) {
// Create command list
static const VGubyte rectCommands[] = {
VG_MOVE_TO_ABS,
@@ -95,6 +118,34 @@ void QSGOpenVGRectangleNode::render()
coordinates[4] = -m_rect.width();
vgAppendPathData(m_rectPath, 5, rectCommands, coordinates.constData());
+
+ } else {
+ // Pre-transform path
+ static const VGubyte rectCommands[] = {
+ VG_MOVE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_LINE_TO_ABS,
+ VG_CLOSE_PATH
+ };
+
+ QVector<VGfloat> coordinates(8);
+ const QPointF topLeft = transform().map(m_rect.topLeft());
+ const QPointF topRight = transform().map(m_rect.topRight());
+ const QPointF bottomLeft = transform().map(m_rect.bottomLeft());
+ const QPointF bottomRight = transform().map(m_rect.bottomRight());
+ coordinates[0] = bottomLeft.x();
+ coordinates[1] = bottomLeft.y();
+ coordinates[2] = bottomRight.x();
+ coordinates[3] = bottomRight.y();
+ coordinates[4] = topRight.x();
+ coordinates[5] = topRight.y();
+ coordinates[6] = topLeft.x();
+ coordinates[7] = topLeft.y();
+
+ vgAppendPathData(m_rectPath, 5, rectCommands, coordinates.constData());
+ }
+
m_pathDirty = false;
}
@@ -155,6 +206,10 @@ void QSGOpenVGImageNode::render()
vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
}
+ // Set Transform
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(transform().constData());
+
VGImage image = static_cast<VGImage>(m_texture->textureId());
//Apply the TextureCoordinateTransform Flag
@@ -251,6 +306,10 @@ void QSGOpenVGNinePatchNode::render()
vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
}
+ // Set Transform
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(transform().constData());
+
VGImage image = static_cast<VGImage>(m_texture->textureId());
//Draw borderImage
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.h b/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.h
index 70b087e9fc..34c8e50615 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.h
@@ -64,6 +64,8 @@ public:
void setColor(const QColor &color) override;
QColor color() const override { return m_color; }
+ void setTransform(const QOpenVGMatrix &transform) override;
+
void render() override;
private:
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderable.cpp b/src/plugins/scenegraph/openvg/qsgopenvgrenderable.cpp
index 0856acfc9a..97d0be99c8 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgrenderable.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderable.cpp
@@ -74,4 +74,14 @@ VGPaint QSGOpenVGRenderable::opacityPaint() const
return m_opacityPaint;
}
+void QSGOpenVGRenderable::setTransform(const QOpenVGMatrix &transform)
+{
+ m_transform = transform;
+}
+
+const QOpenVGMatrix &QSGOpenVGRenderable::transform() const
+{
+ return m_transform;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderable.h b/src/plugins/scenegraph/openvg/qsgopenvgrenderable.h
index 7a09f2afbe..a544ae743e 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgrenderable.h
+++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderable.h
@@ -44,6 +44,8 @@
#include <VG/openvg.h>
+#include "qopenvgmatrix.h"
+
QT_BEGIN_NAMESPACE
class QSGOpenVGRenderable
@@ -58,9 +60,13 @@ public:
float opacity() const;
VGPaint opacityPaint() const;
+ virtual void setTransform(const QOpenVGMatrix &transform);
+ const QOpenVGMatrix &transform() const;
+
private:
float m_opacity;
VGPaint m_opacityPaint;
+ QOpenVGMatrix m_transform;
};
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp
index 9bce12c83f..fb24df7471 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp
@@ -138,6 +138,10 @@ void QSGOpenVGSpriteNode::render()
vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
}
+ // Set Image Matrix
+ vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+ vgLoadMatrix(transform().constData());
+
if (sourceRect != targetRect) {
// Scale
float scaleX = targetRect.width() / sourceRect.width();