From bbc137eabe0dc5ac62afa682710e4b8535dd415d Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Sun, 21 Aug 2011 21:36:41 +1000 Subject: [PATCH] Added initial CachedSvgItem implementation Texture is regenerated each time item is scaled but it's reused during rotation, unlike the default DeviceCoordinateCache mode. --- .../src/libs/utils/cachedsvgitem.cpp | 155 ++++++++++++++++++ .../src/libs/utils/cachedsvgitem.h | 52 ++++++ ground/openpilotgcs/src/libs/utils/utils.pro | 10 +- 3 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 ground/openpilotgcs/src/libs/utils/cachedsvgitem.cpp create mode 100644 ground/openpilotgcs/src/libs/utils/cachedsvgitem.h diff --git a/ground/openpilotgcs/src/libs/utils/cachedsvgitem.cpp b/ground/openpilotgcs/src/libs/utils/cachedsvgitem.cpp new file mode 100644 index 000000000..4fc80e6d2 --- /dev/null +++ b/ground/openpilotgcs/src/libs/utils/cachedsvgitem.cpp @@ -0,0 +1,155 @@ +/** + ****************************************************************************** + * + * @file cachedsvgitem.h + * @author Dmytro Poplavskiy Copyright (C) 2011. + * @{ + * @brief OpenGL texture cached SVG item + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "cachedsvgitem.h" +#include +#include + +CachedSvgItem::CachedSvgItem(QGraphicsItem * parent) : + QGraphicsSvgItem(parent), + m_context(0), + m_texture(0), + m_scale(1.0) +{ + setCacheMode(NoCache); +} + +CachedSvgItem::CachedSvgItem(const QString & fileName, QGraphicsItem * parent): + QGraphicsSvgItem(fileName, parent), + m_context(0), + m_texture(0), + m_scale(1.0) +{ + setCacheMode(NoCache); +} + +CachedSvgItem::~CachedSvgItem() +{ + if (m_context && m_texture) { + m_context->makeCurrent(); + glDeleteTextures(1, &m_texture); + } +} + +void CachedSvgItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + + if (painter->paintEngine()->type() != QPaintEngine::OpenGL && + painter->paintEngine()->type() != QPaintEngine::OpenGL2) { + //Fallback to direct painting + QGraphicsSvgItem::paint(painter, option, widget); + return; + } + + QRectF br = boundingRect(); + QTransform transform = painter->worldTransform(); + qreal sceneScale = transform.map(QLineF(0,0,1,0)).length(); + + bool stencilTestEnabled = glIsEnabled(GL_STENCIL_TEST); + bool scissorTestEnabled = glIsEnabled(GL_SCISSOR_TEST); + + painter->beginNativePainting(); + + if (stencilTestEnabled) + glEnable(GL_STENCIL_TEST); + if (scissorTestEnabled) + glEnable(GL_SCISSOR_TEST); + + bool dirty = false; + if (!m_texture) { + glGenTextures(1, &m_texture); + m_context = const_cast(QGLContext::currentContext()); + + dirty = true; + } + + if (!qFuzzyCompare(sceneScale, m_scale)) { + m_scale = sceneScale; + dirty = true; + } + + int textureWidth = (int(br.width()*m_scale) + 3) & ~3; + int textureHeight = (int(br.height()*m_scale) + 3) & ~3; + + if (dirty) { + //qDebug() << "re-render image"; + + QImage img(textureWidth, textureHeight, QImage::Format_ARGB32); + { + img.fill(Qt::transparent); + QPainter p; + p.begin(&img); + p.setRenderHints(painter->renderHints()); + p.translate(br.topLeft()); + p.scale(m_scale, m_scale); + QGraphicsSvgItem::paint(&p, option, 0); + p.end(); + + img = img.rgbSwapped(); + } + + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, m_texture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + textureWidth, + textureHeight, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + img.bits()); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glDisable(GL_TEXTURE_2D); + + dirty = false; + } + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_TEXTURE_2D); + + glBindTexture(GL_TEXTURE_2D, m_texture); + + //texture may be slightly large than svn image, ensure only used area is rendered + qreal tw = br.width()*m_scale/textureWidth; + qreal th = br.height()*m_scale/textureHeight; + + glBegin(GL_QUADS); + glTexCoord2d(0, 0 ); glVertex3d(br.left(), br.top(), -1); + glTexCoord2d(tw, 0 ); glVertex3d(br.right(), br.top(), -1); + glTexCoord2d(tw, th); glVertex3d(br.right(), br.bottom(), -1); + glTexCoord2d(0, th); glVertex3d(br.left(), br.bottom(), -1); + glEnd(); + glDisable(GL_TEXTURE_2D); + + painter->endNativePainting(); +} diff --git a/ground/openpilotgcs/src/libs/utils/cachedsvgitem.h b/ground/openpilotgcs/src/libs/utils/cachedsvgitem.h new file mode 100644 index 000000000..19f9fd4eb --- /dev/null +++ b/ground/openpilotgcs/src/libs/utils/cachedsvgitem.h @@ -0,0 +1,52 @@ +/** + ****************************************************************************** + * + * @file cachedsvgitem.h + * @author Dmytro Poplavskiy Copyright (C) 2011. + * @{ + * @brief OpenGL texture cached SVG item + *****************************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CACHEDSVGITEM_H +#define CACHEDSVGITEM_H + +#include +#include + +class QGLContext; + +//Cache Svg item as GL Texture. +//Texture is regenerated each time item is scaled +//but it's reused during rotation, unlike DeviceCoordinateCache mode +class CachedSvgItem: public QGraphicsSvgItem +{ + Q_OBJECT +public: + CachedSvgItem(QGraphicsItem * parent = 0); + CachedSvgItem(const QString & fileName, QGraphicsItem * parent = 0); + ~CachedSvgItem(); + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + +private: + QGLContext *m_context; + GLuint m_texture; + qreal m_scale; +}; + +#endif diff --git a/ground/openpilotgcs/src/libs/utils/utils.pro b/ground/openpilotgcs/src/libs/utils/utils.pro index 804f7c813..003497b4d 100644 --- a/ground/openpilotgcs/src/libs/utils/utils.pro +++ b/ground/openpilotgcs/src/libs/utils/utils.pro @@ -3,7 +3,9 @@ TARGET = Utils QT += gui \ network \ - xml + xml \ + svg \ + opengl DEFINES += QTCREATOR_UTILS_LIB @@ -48,7 +50,8 @@ SOURCES += reloadpromptutils.cpp \ homelocationutil.cpp \ mytabbedstackwidget.cpp \ mytabwidget.cpp \ - mylistwidget.cpp + mylistwidget.cpp \ + cachedsvgitem.cpp SOURCES += xmlconfig.cpp win32 { @@ -102,7 +105,8 @@ HEADERS += utils_global.h \ homelocationutil.h \ mytabbedstackwidget.h \ mytabwidget.h \ - mylistwidget.h + mylistwidget.h \ + cachedsvgitem.h HEADERS += xmlconfig.h FORMS += filewizardpage.ui \