diff options
author | Gunnar Sletta <gunnar.sletta@digia.com> | 2013-05-26 20:31:40 +0200 |
---|---|---|
committer | Gunnar Sletta <gunnar.sletta@digia.com> | 2013-05-28 09:29:08 +0200 |
commit | 1837bafc23d252fc7a7e9b86618d6e688063b17f (patch) | |
tree | f7c03c3e1cb5062b6dad1668770e0aeaaa45c4c6 | |
parent | baaa6d691a1820c80670ee7cfd727fb1c2c7b832 (diff) |
Say hello to Qt.labs.shapes 0.1
The shapes plugin provies three element types.
1. TriangleSet - which encapsulates a set of triangles
including read/save logic to a very basic textual
format. Binary can of course be added later... It
also contains a set of path commands and uses Qt's
triangulator internally to convert a path into
triangles.
2. Polygon - Renders a flat shaded triangle set.
3. MaskedImage - Reads two triangle sets in addition
to an image and splits the image into a opaque and
blended part, making it possible to greatly reduce
the blending needed for drawing large bitmaps which are
largely opaque.
There is also a maskmaker tool in the tools subdirectory
which provides a simple means of generating masks for the
MaskedImage
Change-Id: Ia00f059fb81872e6ca1dca78baf3073c9581acab
Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
-rw-r--r-- | shapes/shapes.pro | 2 | ||||
-rw-r--r-- | shapes/shapesplugin/qmldir | 2 | ||||
-rw-r--r-- | shapes/shapesplugin/qsgmaskedimage.cpp | 266 | ||||
-rw-r--r-- | shapes/shapesplugin/qsgmaskedimage.h | 82 | ||||
-rw-r--r-- | shapes/shapesplugin/qsgpolygon.cpp | 140 | ||||
-rw-r--r-- | shapes/shapesplugin/qsgpolygon.h | 82 | ||||
-rw-r--r-- | shapes/shapesplugin/qsgtriangleset.cpp | 302 | ||||
-rw-r--r-- | shapes/shapesplugin/qsgtriangleset.h | 107 | ||||
-rw-r--r-- | shapes/shapesplugin/shapesplugin.cpp | 62 | ||||
-rw-r--r-- | shapes/shapesplugin/shapesplugin.pro | 29 | ||||
-rw-r--r-- | shapes/tests/TestMaskedImage.qml | 77 | ||||
-rw-r--r-- | shapes/tests/TestPolygon.qml | 96 | ||||
-rw-r--r-- | shapes/tests/TestVectorPath.qml | 71 | ||||
-rw-r--r-- | shapes/tests/qtlogo.png | bin | 0 -> 35860 bytes | |||
-rw-r--r-- | shapes/tests/qtlogo.png.alphamask | 75 | ||||
-rw-r--r-- | shapes/tests/qtlogo.png.opaquemask | 41 | ||||
-rw-r--r-- | shapes/tools/maskmaker/Checkers.qml | 68 | ||||
-rw-r--r-- | shapes/tools/maskmaker/Main.qml | 330 | ||||
-rw-r--r-- | shapes/tools/maskmaker/maskmaker.cpp | 97 | ||||
-rw-r--r-- | shapes/tools/maskmaker/maskmaker.pro | 9 | ||||
-rw-r--r-- | shapes/tools/maskmaker/maskmaker.qrc | 6 |
21 files changed, 1944 insertions, 0 deletions
diff --git a/shapes/shapes.pro b/shapes/shapes.pro new file mode 100644 index 0000000..5da5d4c --- /dev/null +++ b/shapes/shapes.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS += shapesplugin tools/maskmaker diff --git a/shapes/shapesplugin/qmldir b/shapes/shapesplugin/qmldir new file mode 100644 index 0000000..7ee1dd5 --- /dev/null +++ b/shapes/shapesplugin/qmldir @@ -0,0 +1,2 @@ +module Qt.labs.shapes +plugin shapes diff --git a/shapes/shapesplugin/qsgmaskedimage.cpp b/shapes/shapesplugin/qsgmaskedimage.cpp new file mode 100644 index 0000000..6309aa3 --- /dev/null +++ b/shapes/shapesplugin/qsgmaskedimage.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgmaskedimage.h" +#include <QtQml/QQmlFile> + +#include <QtQuick/QSGGeometryNode> +#include <QtQuick/QSGTexture> +#include <QtQuick/QSGTextureMaterial> +#include <QtQuick/QQuickWindow> + +#include <private/qquickpixmapcache_p.h> +#include <private/qquickimagebase_p_p.h> + +namespace QSGMaskedImageNS +{ + +class Mesh : public QSGGeometryNode +{ +public: + + Mesh() + : geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0, 0) + { + setGeometry(&geometry); + setMaterial(&material); + setOpaqueMaterial(&opaqueMaterial); + setFlags(OwnedByParent | OwnsOpaqueMaterial | OwnsMaterial | OwnsGeometry, false); + geometry.setDrawingMode(GL_TRIANGLE_STRIP); + } + + void setTexture(QSGTexture *texture) { + opaqueMaterial.setTexture(texture); + material.setTexture(texture); + } + + void setTriangles(QSGTriangleSet *t) { + Q_ASSERT_X(t->vertexType() == QSGTriangleSet::IndexedPoint2D, "QSGMaskedImage", "only IndexedPoint2D is supported by masked image"); + + QVector<QSGGeometry::Point2D> vertices = t->vertices2D(); + QVector<quint16> indices = t->indices(); + geometry.allocate(vertices.size(), indices.size()); + geometry.setDrawingMode(t->drawingMode()); + + QSGGeometry::TexturedPoint2D *v = geometry.vertexDataAsTexturedPoint2D(); + for (int i=0; i<vertices.size(); ++i) { + const QSGGeometry::Point2D &pt = vertices.at(i); + v[i].set(pt.x, pt.y, pt.x, pt.y); + } + + quint16 *in = geometry.indexDataAsUShort(); + memcpy(in, indices.constData(), indices.size() * sizeof(quint16)); + } + + QSGOpaqueTextureMaterial opaqueMaterial; + QSGTextureMaterial material; + QSGGeometry geometry; +}; + +class Root : public QSGTransformNode +{ +public: + Root() + { +#ifdef QML_RUNTIME_TESTING + description = "MaskedImage"; + opaque.description = QStringLiteral("MaskedImage.opaque"); + alpha.description = QStringLiteral("MaskedImage.alpha"); +#endif + } + + void setTexture(QSGTexture *t) { + alpha.setTexture(t); + opaque.setTexture(t); + // Disable blending on this node as setTexture will set it to true. + opaque.opaqueMaterial.setFlag(QSGMaterial::Blending, false); + opaque.material.setFlag(QSGMaterial::Blending, false); + } + + Mesh opaque; + Mesh alpha; +}; + + + +class MaskStore : public QObject +{ + Q_OBJECT + +public: + static QSGTriangleSet *lookup(QQuickTextureFactory *factory, const QString &url, bool opaque); + +public slots: + void factoryDestroyed(QObject *o); + +private: + QHash<qintptr, QSGTriangleSet *> store; + + static MaskStore instance; +}; + +MaskStore MaskStore::instance; + +QSGTriangleSet *MaskStore::lookup(QQuickTextureFactory *factory, const QString &url, bool opaque) +{ + qintptr key = (qintptr) factory; + if (opaque) + key += 1; + + if (instance.store.contains(key)) + return instance.store.value(key); + + QSGTriangleSet *set = new QSGTriangleSet(); + QString res = set->readFile(url); + if (res.length() > 0) { + qDebug() << "Failed to read" << url << "," << res; + delete set; + set = 0; + } + + // Only connect to opaque to avoid connecting twice... + if (opaque) + connect(factory, SIGNAL(destroyed(QObject *)), &instance, SLOT(factoryDestroyed(QObject *))); + + instance.store[key] = set; + return set; +} + +void MaskStore::factoryDestroyed(QObject *o) +{ + QQuickTextureFactory *f = static_cast<QQuickTextureFactory *>(o); + store.remove(qintptr(f)); + store.remove(qintptr(f) + 1); +} + +} + +using namespace QSGMaskedImageNS; + + +QSGMaskedImage::QSGMaskedImage(QQuickItem *parent) + : QQuickImageBase(parent) + , m_opaqueTriangles(0) + , m_alphaTriangles(0) + , m_sourceChanged(false) +{ + setFlag(ItemHasContents, true); + + connect(this, SIGNAL(widthChanged()), this, SLOT(sizeWasChanged())); + connect(this, SIGNAL(heightChanged()), this, SLOT(sizeWasChanged())); +} + +QSGMaskedImage::~QSGMaskedImage() +{ + +} + +void QSGMaskedImage::pixmapChange() +{ + m_sourceChanged = true; + polish(); + QQuickImageBase::pixmapChange(); +} + +void QSGMaskedImage::updatePolish() +{ + if (m_sourceChanged) { + QString baseName = QQmlFile::urlToLocalFileOrQrc(source()); + m_opaqueTriangles = MaskStore::lookup(static_cast<QQuickImageBasePrivate *>(d_ptr.data())->pix.textureFactory(), + baseName + QStringLiteral(".opaquemask"), + true); + m_alphaTriangles = MaskStore::lookup(static_cast<QQuickImageBasePrivate *>(d_ptr.data())->pix.textureFactory(), + baseName + QStringLiteral(".alphamask"), + false); + } + + update(); +} + +void QSGMaskedImage::sizeWasChanged() +{ + update(); +} + +QSGNode *QSGMaskedImage::updatePaintNode(QSGNode *old, UpdatePaintNodeData *) +{ + Root *node = static_cast<Root *>(old); + + if (m_sourceChanged) { + QQuickPixmap *pix = &static_cast<QQuickImageBasePrivate *>(d_ptr.data())->pix; + delete node; + if (pix->isNull()) + return 0; + + node = new Root(); + + QSGTexture *t = pix->textureFactory()->createTexture(window()); + node->setTexture(t); + m_sourceChanged = false; + + if (m_alphaTriangles && m_alphaTriangles->isValid()) { + node->alpha.setTriangles(m_alphaTriangles); + node->appendChildNode(&node->alpha); + } + + if (m_opaqueTriangles && m_opaqueTriangles->isValid()) { + node->opaque.setTriangles(m_opaqueTriangles); + node->appendChildNode(&node->opaque); + } + } + + if (!node) + return 0; + + QSGTexture::Filtering filter = smooth() ? QSGTexture::Linear : QSGTexture::Nearest; + node->opaque.material.setFiltering(filter); + node->opaque.opaqueMaterial.setFiltering(filter); + node->alpha.material.setFiltering(filter); + node->alpha.opaqueMaterial.setFiltering(filter); + + QMatrix4x4 m; + m.scale(width(), height()); + node->setMatrix(m); + + return node; +} + +#include "qsgmaskedimage.moc" diff --git a/shapes/shapesplugin/qsgmaskedimage.h b/shapes/shapesplugin/qsgmaskedimage.h new file mode 100644 index 0000000..299794b --- /dev/null +++ b/shapes/shapesplugin/qsgmaskedimage.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGMASKEDIMAGE_H +#define QSGMASKEDIMAGE_H + +#include <private/qquickimagebase_p.h> + +#include <QtGui/QImage> + +#include "qsgtriangleset.h" + +class QSGMaskedImage : public QQuickImageBase +{ + Q_OBJECT + +public: + QSGMaskedImage(QQuickItem *parent = 0); + ~QSGMaskedImage(); + +protected: + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + void updatePolish(); + + void pixmapChange(); + +public slots: + void sizeWasChanged(); + +signals: + void sourceChanged(QUrl source); + +private: + QSGTriangleSet *m_opaqueTriangles; + QSGTriangleSet *m_alphaTriangles; + + uint m_sourceChanged : 1; + uint m_explicitSize : 1; +}; + +QML_DECLARE_TYPE(QSGMaskedImage) + +#endif // QSGMASKEDIMAGE_H + diff --git a/shapes/shapesplugin/qsgpolygon.cpp b/shapes/shapesplugin/qsgpolygon.cpp new file mode 100644 index 0000000..7741126 --- /dev/null +++ b/shapes/shapesplugin/qsgpolygon.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgpolygon.h" + +#include <QtQuick/qsgnode.h> +#include <QtQuick/qsgflatcolormaterial.h> + +// #define QSGPOLYGON_DEBUG + +class QSGPolygonNode : public QSGGeometryNode +{ +public: + QSGPolygonNode() + : g(QSGGeometry::defaultAttributes_Point2D(), 0, 0) + { + setGeometry(&g); + setMaterial(&m); + setFlags(OwnsGeometry | OwnsMaterial, false); + } + + QSGGeometry g; + QSGFlatColorMaterial m; +}; + +QSGPolygon::QSGPolygon() + : m_triangleSet(0) + , m_color(Qt::white) + , m_colorWasChanged(false) + , m_triangleSetWasChanged(false) +{ + setFlag(ItemHasContents, true); +} + +void QSGPolygon::setTriangleSet(QSGTriangleSet *set) +{ + if (set == m_triangleSet) + return; + + if (m_triangleSet) + disconnect(m_triangleSet, SIGNAL(changed()), this, SLOT(update())); + m_triangleSet = set; + connect(m_triangleSet, SIGNAL(changed()), this, SLOT(update())); + + m_triangleSetWasChanged = true; + + emit triangleSetChanged(m_triangleSet); + update(); +} + +void QSGPolygon::setColor(const QColor &color) +{ + if (color == m_color) + return; + + m_color = color; + + m_colorWasChanged = true; + emit colorChanged(m_color); + update(); +} + +QSGNode *QSGPolygon::updatePaintNode(QSGNode *old, UpdatePaintNodeData *) +{ + QSGPolygonNode *n = static_cast<QSGPolygonNode *>(old); + + if (m_triangleSet == 0 || !m_triangleSet->isValid() || !m_color.isValid() || m_color.alpha() == 0) { + delete n; + return 0; + } + + if (!n) + n = new QSGPolygonNode(); + + if (m_triangleSetWasChanged) { + QSGGeometry *g = &n->g; + g->allocate(m_triangleSet->vertices2D().size(), m_triangleSet->indices().size()); + g->setDrawingMode(m_triangleSet->drawingMode()); + + memcpy(g->vertexData(), m_triangleSet->vertices2D().constData(), g->sizeOfVertex() * g->vertexCount()); + memcpy(g->indexData(), m_triangleSet->indices().constData(), g->sizeOfIndex() * g->indexCount()); + +#ifdef QSGPOLYGON_DEBUG + for (int i=0; i<g->vertexCount(); ++i) + qDebug() << "Polygon Vertex:" << g->vertexDataAsPoint2D()[i].x << g->vertexDataAsPoint2D()[i].y; + for (int i=0; i<g->indexCount(); ++i) + qDebug() << "Polygon Index:" << g->indexDataAsUShort()[i]; +#endif + + n->markDirty(QSGNode::DirtyGeometry); + m_triangleSetWasChanged = false; + } + + if (m_colorWasChanged) { + n->m.setColor(m_color); + m_colorWasChanged = false; + n->markDirty(QSGNode::DirtyMaterial); + } + + return n; +} + diff --git a/shapes/shapesplugin/qsgpolygon.h b/shapes/shapesplugin/qsgpolygon.h new file mode 100644 index 0000000..b5c1f8c --- /dev/null +++ b/shapes/shapesplugin/qsgpolygon.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGPOLYGON_H +#define QSGPOLYGON_H + +#include <QtQuick/QQuickItem> + +#include "qsgtriangleset.h" + +class QSGPolygon : public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(QSGTriangleSet *triangleSet READ triangleSet WRITE setTriangleSet NOTIFY triangleSetChanged) + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) +public: + QSGPolygon(); + + QSGTriangleSet *triangleSet() const { return m_triangleSet; } + QColor color() const { return m_color; } + +protected: + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + +signals: + void triangleSetChanged(QSGTriangleSet *set); + void colorChanged(const QColor &color); + +public slots: + void setTriangleSet(QSGTriangleSet *set); + void setColor(const QColor &color); + +private: + QSGTriangleSet *m_triangleSet; + QColor m_color; + + uint m_colorWasChanged : 1; + uint m_triangleSetWasChanged : 1; +}; + +QML_DECLARE_TYPE(QSGPolygon) + +#endif diff --git a/shapes/shapesplugin/qsgtriangleset.cpp b/shapes/shapesplugin/qsgtriangleset.cpp new file mode 100644 index 0000000..64d876f --- /dev/null +++ b/shapes/shapesplugin/qsgtriangleset.cpp @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgtriangleset.h" + +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QTextStream> +#include <QtCore/QDebug> + +#include <QtGui/QTransform> + +#include <private/qpolygonclipper_p.h> + +#include <private/qtriangulator_p.h> + +// #define QSGTRIANGLESET_DEBUG + +QSGTriangleSet::QSGTriangleSet() + : QObject() + , m_mode(GL_TRIANGLES) + , m_vertexType(IndexedPoint2D) +{ +} + + +void QSGTriangleSet::setDrawingMode(int drawingMode) +{ + if (m_mode == drawingMode) + return; + + switch (drawingMode) { + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_LINES: + m_mode = drawingMode; + break; + default: + qWarning("QSGTriangleSet::setDrawingMode: mode is unsupported: %d", drawingMode); + return; + } + + emit changed(); +} + +void QSGTriangleSet::setVertexType(VertexType type) +{ + m_vertexType = type; + emit changed(); +} + +/* + * Reads the file and returns an empty string if it fails. + */ + +QString QSGTriangleSet::readFile(const QUrl &name) +{ + QFile file(name.isRelative() ? name.toString() : name.toLocalFile()); + if (!file.open(QFile::ReadOnly)) + return file.errorString() + QStringLiteral(", ") + QFileInfo(file).absoluteFilePath(); + + QTextStream stream(&file); + + QByteArray tag, version; + + stream >> tag; + stream >> version; + if (tag != "qsgtriangleset") + return "not a triangleset file"; + if (version != "0.1") + return "invalid version, only 0.1 currently supported"; + + stream >> tag; + QByteArray value; + + int drawingMode = -1; + int vertexType = -1; + + // Parse the rest of the header... + while (tag != "v" && tag != "V") { + if (tag == "drawing-mode") { + stream >> value; + if (value == "triangle-strip") drawingMode = GL_TRIANGLE_STRIP; + else if (value == "triangle-fan") drawingMode = GL_TRIANGLE_FAN; + else if (value == "triangles") drawingMode = GL_TRIANGLES; + else if (value == "lines") drawingMode = GL_LINES; + else return "bad drawing-mode: " + value; + } else if (tag == "data-type") { + stream >> value; + if (value == "indexed-point-2d") vertexType = IndexedPoint2D; + else return "bad data-type: " + value; + } + + stream >> tag; + + if (stream.atEnd()) + return "premature end of file while parsing headers..."; + } + + if (drawingMode == -1) + return QStringLiteral("missing drawing-mode tag..."); + if (vertexType == -1) + return QStringLiteral("missing vertex-type tag..."); + + QVector<QSGGeometry::Point2D> vertices; + + // Parse vertices... + while (tag == "V" || tag == "v") { + QSGGeometry::Point2D p; + stream >> p.x >> p.y; + vertices << p; + stream >> tag; + } + if (vertices.size() == 0) + return "no vertices"; + + QVector<quint16> indices; + while (tag == "I" || tag == "i") { + quint16 i; + stream >> i; + indices << i; + stream >> tag; + } + + if (indices.size() == 0) + return "no indices..."; + + m_indices = indices; + m_vertices = vertices; + m_mode = drawingMode; + m_vertexType = (VertexType) vertexType; + + emit changed(); + + return QString(); +} + +QString QSGTriangleSet::saveFile(const QUrl &name) +{ + QFile file(name.isRelative() ? name.toString() : name.toLocalFile()); + if (!file.open(QFile::WriteOnly)) + return QStringLiteral("failed to open file, ") + QFileInfo(file).absoluteFilePath(); + + QTextStream stream(&file); + + stream << "qsgtriangleset 0.1" << endl + << "drawing-mode "; + if (m_mode == GL_TRIANGLES) + stream << "triangles"; + else if (m_mode == GL_TRIANGLE_STRIP) + stream << "triangle-strip"; + else if (m_mode == GL_TRIANGLE_FAN) + stream << "triangle-fan"; + else if (m_mode == GL_LINES) + stream << "lines"; + stream << endl << "data-type indexed-point-2d" << endl; + + for (int i=0; i<m_vertices.size(); ++i) + stream << "V " << m_vertices.at(i).x << " " << m_vertices.at(i).y << endl; + for (int i=0; i<m_indices.size(); ++i) + stream << "I " << m_indices.at(i) << endl; + + return QString(); +} + +void QSGTriangleSet::beginPathConstruction() +{ + m_path = QPainterPath(); +} + +void QSGTriangleSet::moveTo(qreal x, qreal y) +{ + m_path.moveTo(x, y); +} + +void QSGTriangleSet::lineTo(qreal x, qreal y) +{ + m_path.lineTo(x, y); +} + +void QSGTriangleSet::quadTo(qreal cx, qreal cy, qreal ex, qreal ey) +{ + m_path.quadTo(cx, cy, ex, ey); +} + +void QSGTriangleSet::cubicTo(qreal cx1, qreal cy1, qreal cx2, qreal cy2, qreal ex, qreal ey) +{ + m_path.cubicTo(cx1, cy1, cx2, cy2, ex, ey); +} + +void QSGTriangleSet::addEllipse(qreal x, qreal y, qreal width, qreal height) +{ + m_path.addEllipse(x, y, width, height); +} + +void QSGTriangleSet::addRect(qreal x, qreal y, qreal width, qreal height) +{ + m_path.addRect(x, y, width, height); +} + +void QSGTriangleSet::addRoundedRect(qreal x, qreal y, qreal width, qreal height, qreal xrad, qreal yrad) +{ + m_path.addRoundedRect(x, y, width, height, xrad, yrad); +} + +void QSGTriangleSet::closeSubpath() +{ + m_path.closeSubpath(); +} + +void QSGTriangleSet::setWindingMode(bool winding) +{ + m_path.setFillRule(winding ? Qt::WindingFill : Qt::OddEvenFill); +} + +void QSGTriangleSet::clipToRect(qreal x, qreal y, qreal width, qreal height) +{ + QPainterPath bounds; + bounds.addRect(x, y, width, height); + m_path = m_path.intersected(bounds); +} + +void QSGTriangleSet::finishPathConstruction() +{ + qreal scale = 100; + + QTriangleSet ts = qTriangulate(m_path, QTransform::fromScale(scale, scale)); + + m_mode = GL_TRIANGLES; + + m_vertices.resize(ts.vertices.size() / 2); + QSGGeometry::Point2D *vdst = m_vertices.data(); + const qreal *vdata = ts.vertices.constData(); + for (int i=0; i<ts.vertices.size() / 2; ++i) { + vdst[i].set(vdata[i*2] / scale, vdata[i*2+1] / scale); +#ifdef QSGTRIANGLESET_DEBUG + qDebug() << "vertex: " << vdst[i].x << vdst[i].y; +#endif + } + + m_indices.resize(ts.indices.size()); + quint16 *idst = m_indices.data(); + if (ts.indices.type() == QVertexIndexVector::UnsignedShort) { + memcpy(idst, ts.indices.data(), m_indices.size() * sizeof(quint16)); +#ifdef QSGTRIANGLESET_DEBUG + for (int i=0; i<m_indices.size(); ++i) { + qDebug() << "index(16): " << idst[i]; + } +#endif + } else { + const quint32 *isrc = (const quint32 *) ts.indices.data(); + for (int i=0; i<m_indices.size(); ++i) { + idst[i] = isrc[i]; +#ifdef QSGTRIANGLESET_DEBUG + qDebug() << "index: " << idst[i]; +#endif + } + } + + emit changed(); + +} + diff --git a/shapes/shapesplugin/qsgtriangleset.h b/shapes/shapesplugin/qsgtriangleset.h new file mode 100644 index 0000000..4ca84a6 --- /dev/null +++ b/shapes/shapesplugin/qsgtriangleset.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGTRIANGLESET_H +#define QSGTRIANGLESET_H + +#include <QObject> + +#include <QtGui/QPainterPath> + +#include <QtQuick/qsggeometry.h> +#include <QtQuick/QQuickItem> + +class QSGTriangleSet : public QObject +{ + Q_OBJECT + + Q_PROPERTY(int drawingMode READ drawingMode WRITE setDrawingMode NOTIFY changed) + +public: + enum VertexType { + IndexedPoint2D + }; + + QSGTriangleSet(); + + QVector<quint16> indices() const { return m_indices; } + QVector<QSGGeometry::Point2D> vertices2D() const { return m_vertices; } + + int drawingMode() const { return m_mode; } + void setDrawingMode(int drawingMode); + + VertexType vertexType() const { return m_vertexType; } + void setVertexType(VertexType type); + + bool isValid() const { return m_indices.size() > 0 && m_vertices.size() > 0; } + +public slots: + QString readFile(const QUrl &name); + QString saveFile(const QUrl &name); + + void beginPathConstruction(); + void moveTo(qreal x, qreal y); + void lineTo(qreal x, qreal y); + void quadTo(qreal cx, qreal cy, qreal ex, qreal ey); + void cubicTo(qreal cx1, qreal cy1, qreal cx2, qreal cy2, qreal ex, qreal ey); + void addEllipse(qreal x, qreal y, qreal width, qreal height); + void addRect(qreal x, qreal y, qreal width, qreal height); + void addRoundedRect(qreal x, qreal y, qreal width, qreal height, qreal xrad, qreal yrad); + void setWindingMode(bool winding); + void closeSubpath(); + void clipToRect(qreal x, qreal y, qreal width, qreal height); + void finishPathConstruction(); + +signals: + void changed(); + +private: + int m_mode; + VertexType m_vertexType; + QVector<quint16> m_indices; + QVector<QSGGeometry::Point2D> m_vertices; + + QPainterPath m_path; +}; + +QML_DECLARE_TYPE(QSGTriangleSet) + +#endif // QSGTRIANGLESET_H diff --git a/shapes/shapesplugin/shapesplugin.cpp b/shapes/shapesplugin/shapesplugin.cpp new file mode 100644 index 0000000..248ad85 --- /dev/null +++ b/shapes/shapesplugin/shapesplugin.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QQmlExtensionPlugin> + +#include "qsgmaskedimage.h" +#include "qsgpolygon.h" +#include "qsgtriangleset.h" + +class MaskedimagepluginPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + void registerTypes(const char *uri) + { + qmlRegisterType<QSGMaskedImage>(uri, 1, 0, "MaskedImage"); + qmlRegisterType<QSGPolygon>(uri, 1, 0, "Polygon"); + qmlRegisterType<QSGTriangleSet>(uri, 1, 0, "TriangleSet"); + } +}; + +#include "shapesplugin.moc" diff --git a/shapes/shapesplugin/shapesplugin.pro b/shapes/shapesplugin/shapesplugin.pro new file mode 100644 index 0000000..e0150ab --- /dev/null +++ b/shapes/shapesplugin/shapesplugin.pro @@ -0,0 +1,29 @@ +TEMPLATE = lib +TARGET = shapes + +QT += quick +QT += v8-private qml-private quick-private gui-private core-private # to get access to QPainter's triangulator + +CONFIG += qt plugin + +SOURCES += \ + shapesplugin.cpp \ + qsgmaskedimage.cpp \ + qsgtriangleset.cpp \ + qsgpolygon.cpp + +HEADERS += \ + qsgmaskedimage.h \ + qsgtriangleset.h \ + qsgpolygon.h + +TARGETPATH=Qt/labs/shapes + +OTHER_FILES = qmldir + +target.path = $$[QT_INSTALL_QML]/$$TARGETPATH + +qmldir.files = qmldir +qmldir.path = $$[QT_INSTALL_QML]/$$TARGETPATH + +INSTALLS = target qmldir diff --git a/shapes/tests/TestMaskedImage.qml b/shapes/tests/TestMaskedImage.qml new file mode 100644 index 0000000..28dd7a9 --- /dev/null +++ b/shapes/tests/TestMaskedImage.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +import Qt.labs.shapes 1.0 + +Rectangle { + width: 800 + height: 800 + + gradient: Gradient { + GradientStop { position: 0; color: "steelblue" } + GradientStop { position: 1; color: "black" } + } + + MaskedImage { + anchors.centerIn: parent + source: "qtlogo.png" + + asynchronous: true + + opacity: status == Image.Ready ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 500 } } + } + + MaskedImage { + anchors.centerIn: parent + source: "qtlogo.png" + + asynchronous: true + + scale: 0.2 + + opacity: status == Image.Ready ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: 500 } } + } + +} diff --git a/shapes/tests/TestPolygon.qml b/shapes/tests/TestPolygon.qml new file mode 100644 index 0000000..48ca069 --- /dev/null +++ b/shapes/tests/TestPolygon.qml @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +import Qt.labs.shapes 1.0 + +Rectangle { + width: 1280 + height: 720 + + gradient: Gradient { + GradientStop { position: 0; color: "steelblue" } + GradientStop { position: 1; color: "black" } + } + + Polygon { + x: 150 + y: 50 + + color: "white" + triangleSet: TriangleSet { + Component.onCompleted: { + var result = readFile(Qt.resolvedUrl("qtlogo.png.alphamask")) + if (result == "") + print("loaded file ok.." + Qt.resolvedUrl("qtlogo.png.alphamask")); + else + print("failed to load: " + result); + print("loaded file ok.." + Qt.resolvedUrl("qtlogo.png.alphamask")); + } + } + + scale: 600 + opacity: 0.5 + } + + Polygon { + + x: 150 + y: 50 + + color: "lightgray" + triangleSet: TriangleSet { + Component.onCompleted: { + var result = readFile(Qt.resolvedUrl("qtlogo.png.opaquemask")) + if (result == "") + print("loaded file ok.."); + else + print("failed to load: " + result); + } + } + + scale: 600 + + opacity: 0.5 + } + +} diff --git a/shapes/tests/TestVectorPath.qml b/shapes/tests/TestVectorPath.qml new file mode 100644 index 0000000..9f7a7a1 --- /dev/null +++ b/shapes/tests/TestVectorPath.qml @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import Qt.labs.shapes 1.0 + +Rectangle { + width: 600 + height: 600 + + gradient: Gradient { + GradientStop { position: 0; color: "steelblue" } + GradientStop { position: 1; color: "black" } + } + + Polygon { + x: 50 + y: 50 + + color: "white" + triangleSet: TriangleSet { + Component.onCompleted: { + beginPathConstruction(); + addEllipse(100, 100, 200, 200); + addEllipse(200, 200, 200, 200); + moveTo(0, 0); + cubicTo(500, 0, 250, 250, 500, 500); + cubicTo(0, 500, 250, 250, 0, 0); + finishPathConstruction(); + } + } + } +} diff --git a/shapes/tests/qtlogo.png b/shapes/tests/qtlogo.png Binary files differnew file mode 100644 index 0000000..9073a38 --- /dev/null +++ b/shapes/tests/qtlogo.png diff --git a/shapes/tests/qtlogo.png.alphamask b/shapes/tests/qtlogo.png.alphamask new file mode 100644 index 0000000..c35d96a --- /dev/null +++ b/shapes/tests/qtlogo.png.alphamask @@ -0,0 +1,75 @@ +qsgtriangleset 0.1 +drawing-mode triangles +data-type indexed-point-2d +V 0 0.14 +V 0.0065625 0.139687 +V 0.0509375 0.049375 +V 0.22875 0.008125 +V 1 0.116563 +V 1 0.753125 +V 0.986875 0.759375 +V 0.960625 0.831875 +V 0.917813 0.871562 +V 0.080625 0.98625 +V 0 0.92625 +V 0 0.0690625 +V 0.0165625 0.036875 +V 0.0984375 0 +V 0.336563 0 +V 1 0.0884375 +V 1 0.8325 +V 0.9475 0.886563 +V 0.143438 1 +V 0.0621875 1 +V 0 0.955938 +I 13 +I 3 +I 14 +I 13 +I 12 +I 3 +I 12 +I 2 +I 3 +I 12 +I 11 +I 2 +I 11 +I 1 +I 2 +I 11 +I 0 +I 1 +I 3 +I 15 +I 14 +I 3 +I 4 +I 15 +I 6 +I 7 +I 5 +I 7 +I 16 +I 5 +I 7 +I 8 +I 16 +I 8 +I 17 +I 16 +I 8 +I 9 +I 17 +I 9 +I 19 +I 17 +I 19 +I 18 +I 17 +I 20 +I 9 +I 10 +I 20 +I 19 +I 9 diff --git a/shapes/tests/qtlogo.png.opaquemask b/shapes/tests/qtlogo.png.opaquemask new file mode 100644 index 0000000..702dae4 --- /dev/null +++ b/shapes/tests/qtlogo.png.opaquemask @@ -0,0 +1,41 @@ +qsgtriangleset 0.1 +drawing-mode triangles +data-type indexed-point-2d +V 0 0.14 +V 0.0065625 0.139687 +V 0.0509375 0.049375 +V 0.22875 0.008125 +V 1 0.116563 +V 1 0.753125 +V 0.986875 0.759375 +V 0.960625 0.831875 +V 0.917813 0.871562 +V 0.080625 0.98625 +V 0 0.92625 +I 2 +I 4 +I 3 +I 2 +I 1 +I 4 +I 1 +I 0 +I 4 +I 0 +I 5 +I 4 +I 0 +I 6 +I 5 +I 0 +I 7 +I 6 +I 0 +I 8 +I 7 +I 0 +I 10 +I 8 +I 10 +I 9 +I 8 diff --git a/shapes/tools/maskmaker/Checkers.qml b/shapes/tools/maskmaker/Checkers.qml new file mode 100644 index 0000000..a0a78d7 --- /dev/null +++ b/shapes/tools/maskmaker/Checkers.qml @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +import QtQuick 2.0 + +ShaderEffect { + id: tileBackground + + property real tileSize: 16 + property color color1: Qt.rgba(0.9, 0.9, 0.9, 1); + property color color2: Qt.rgba(0.85, 0.85, 0.85, 1); + + property size pixelSize: Qt.size(width / tileSize, height / tileSize); + + fragmentShader: + " + uniform lowp vec4 color1; + uniform lowp vec4 color2; + uniform highp vec2 pixelSize; + varying highp vec2 qt_TexCoord0; + void main() { + highp vec2 tc = sign(sin(3.14152 * qt_TexCoord0 * pixelSize)); + if (tc.x != tc.y) + gl_FragColor = color1; + else + gl_FragColor = color2; + } + " +} diff --git a/shapes/tools/maskmaker/Main.qml b/shapes/tools/maskmaker/Main.qml new file mode 100644 index 0000000..f95b67e --- /dev/null +++ b/shapes/tools/maskmaker/Main.qml @@ -0,0 +1,330 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Scene Graph Playground 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import Qt.labs.shapes 1.0 + +Item { + + id: root; + + width: Math.max(600, imageRoot.width + 200); + height: Math.max(600, imageRoot.height + 200); + + property bool viewFiltered: true + property real aspectRatio: width / height + property string writeMode: "interior" // interior, exterior, none + + property var exterior: [] + property var interior: [] + + property int boxSize: 4 + + Checkers + { + anchors.fill: parent + } + + Item { + id: imageRoot + + visible: image.status == Image.Ready + + anchors.centerIn: parent + width: image.width + height: image.height + + Image { + id: image + property real aspectRatio: width / height + source: "file:" + engine.source; + } + + ShaderEffect { + anchors.fill: parent; + + visible: root.viewFiltered + + blending: false + property variant source: image + fragmentShader: + " + uniform lowp sampler2D source; + varying highp vec2 qt_TexCoord0; + void main() { + lowp float a = texture2D(source, qt_TexCoord0).a; + if (a == 0.0) + gl_FragColor = vec4(0, 0, 0, 1); + else if (a == 1.0) + gl_FragColor = vec4(0.4, 0.4, 0.4, 1); + else + gl_FragColor = vec4(1, 1, 1, 1); + } + " + } + } + + Canvas { + id: overlay + + anchors.fill: parent; + + function drawDots(ctx, list, color) { + ctx.beginPath(); + for (var si=0; si<list.length; ++si) { + var subpath = list[si]; + for (var i=0; i<subpath.length; ++i) { + var p = subpath[i]; + ctx.ellipse(p.x - 6, p.y - 6, 13, 13); + } + } + ctx.fillStyle = color + ctx.fill(); + ctx.strokeStyle = "white" + ctx.stroke(); + } + + function xform(pt) { + return { x: pt.x * imageRoot.width + imageRoot.x, + y: pt.y * imageRoot.height + imageRoot.y }; + } + + function drawShapes(ctx, list, color) { + for (var si=0; si<list.length; ++si) { + var subpath = list[si]; + if (subpath.length >= 3) { + for (var i=0; i<subpath.length; ++i) { + var p = subpath[i]; + if (i == 0) + ctx.moveTo(p.x, p.y); + else + ctx.lineTo(p.x, p.y); + } + } + ctx.closePath(); + } + ctx.fillStyle = color; + ctx.fill(); + ctx.stroke() + } + + onPaint: { + var ctx = overlay.getContext("2d"); + + ctx.clearRect(0, 0, overlay.width, overlay.height); + ctx.reset(); + + ctx.translate(imageRoot.x, imageRoot.y); + + ctx.lineCap = "butt" + ctx.beginPath(); + ctx.globalAlpha = 0.7 + ctx.strokeStyle = "white"; + ctx.fillRule = Qt.OddEvenFill + ctx.lineWidth = 1; + drawShapes(ctx, root.interior, "#aaaaff"); + if (root.exterior.length > 0 && root.exterior[0].length > 2) + drawShapes(ctx, root.exterior, "#ffaaaa"); + + ctx.lineWidth = 2 + ctx.globalAlpha = 1.0; + drawDots(ctx, root.interior, "blue"); + drawDots(ctx, root.exterior, "red"); + + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + onClicked: { + helpOverlay.hidden = true; + var list = root.writeMode == "interior" ? root.interior : root.exterior; + var pt = { x: mouse.x - imageRoot.x, y: mouse.y - imageRoot.y }; + + if (list.length == 0) { + list.push( [ pt ]); + } else { + var subpath = list[list.length - 1]; + if (subpath.length == 0) { + subpath.push(pt) + } else { + var s = subpath[0]; + if (Math.abs(s.x - mouse.x + imageRoot.x) < 20 && Math.abs(s.y - mouse.y + imageRoot.x) < 20 && subpath.length >= 2) { + subpath.push(s); + list.push([]); + } else { + subpath.push(pt); + } + } + } + overlay.requestPaint() + } + } + + TriangleSet { + id: triangleSet + + function add(list) { + for (var si=0; si<list.length; ++si) { + var subpath = list[si]; + if (subpath.length > 0) + moveTo(subpath[0].x / imageRoot.width, subpath[0].y / imageRoot.height); + for (var i=1; i<subpath.length; ++i) + lineTo(subpath[i].x / imageRoot.width, subpath[i].y / imageRoot.height); + closeSubpath() + } + } + + function save() { + if (root.interior.length == 0 || root.interior[0].length < 3 + || root.exterior.length == 0 || root.exterior[0].length < 3) { + helpOverlay.hidden = false; + return; + } + + beginPathConstruction(); + add(root.interior); + clipToRect(0, 0, 1, 1) + finishPathConstruction(); + var or = saveFile(engine.source + ".opaquemask"); + + if (or == "") { + print("saved " + engine.source + ".opaquemask ok..."); + } else { + print("saving " + engine.source + ".opaquemask failed: " + or); + return; + } + + beginPathConstruction(); + add(root.interior); + add(root.exterior); + clipToRect(0, 0, 1, 1); + finishPathConstruction(); + var ar = saveFile(engine.source + ".alphamask"); + if (ar == "") { + print("saved " + engine.source + ".alphamask ok..."); + } else { + print("saving " + engine.source + ".alphamask failed: " + ar); + return; + } + + print("My work here is done...\nGood bye!") + Qt.quit(); + } + } + + Keys.onSpacePressed: root.viewFiltered = !root.viewFiltered; + Keys.onPressed: { + if (event.key == Qt.Key_I) { + root.writeMode = "interior" + } else if (event.key == Qt.Key_E) { + root.writeMode = "exterior" + } else if (event.key == Qt.Key_F1) { + helpOverlay.hidden = !helpOverlay.hidden; + } else if (event.key == Qt.Key_Escape) { + Qt.quit(); + } else if (event.key == Qt.Key_Backspace) { + root.interior = [] + root.exterior = [] + overlay.requestPaint(); + } else if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) { + triangleSet.save() + } + } + + Rectangle { + + id: helpOverlay + + x: parent.width / 2 - width / 2; + y: parent.height / 2- height / 2; + + width: label.width + 40 + height: label.height + 40 + + gradient: Gradient { + GradientStop { position: 0; color: "white" } + GradientStop { position: 1; color: "gray" } + } + property bool hidden: false + opacity: hidden ? 0.0 : 1.0 + Behavior on opacity { NumberAnimation { duration: 100 } } + border.color: "black" + radius: 10 + + enabled: !hidden + + Text { + id: label + font.family: "courier" + text: image.status != Image.Ready ? + "Missing source image. Did you forget to specify it?" : +" +Usage: + +Click to add points to the polygon for interior and exterior. +The interior polygon should mark that which is fully opaque, +visible as gray when the filter is active. The exterior should +be outside all partially translucent pixels, visible as white +when the filter is active. You need at least three nodes in both +interior and exterior before writing the triangles set to disk. + +Shortcuts: + +E: Add to exterior " + (root.writeMode == "exterior" ? "*" : "") + " +I: Add to interior " + (root.writeMode == "interior" ? "*" : "") + " +Backspace: Clear polygons and start over... +F1: Toggle this help +Enter: Save polygons as MaskedImage metadata +Space: Toggle image filter " + (root.viewFiltered ? "*" : "") + " +Escape: Exit... +" + anchors.centerIn: parent; + + } + } + + + focus: true + + +} diff --git a/shapes/tools/maskmaker/maskmaker.cpp b/shapes/tools/maskmaker/maskmaker.cpp new file mode 100644 index 0000000..3f092cb --- /dev/null +++ b/shapes/tools/maskmaker/maskmaker.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Scenegraph Playground module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Digia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/QDebug> +#include <QtGui/QGuiApplication> +#include <QtQml/QQmlContext> +#include <QtQuick/QQuickView> + +class Engine : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString source READ source CONSTANT) +public: + + QString source() const { return m_source; } + void setSource(const QString &src) { m_source = src; } + +private: + QString m_source; +}; + +void printHelp() { + qDebug("Usage:\n" + " > maskmaker [options] filename\n" + "\n" + "Options:\n" + " -h --help This help.."); +} + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + Engine engine; + + QStringList args = app.arguments(); + + for (int i=0; i<args.size(); ++i) { + if (args.at(i) == QStringLiteral("--help") || args.at(i) == QStringLiteral("-h")) { + printHelp(); + return 0; + } else if (i == args.size() - 1 && i > 0) { + engine.setSource(args.at(i)); + } + } + + QQuickView view; + view.rootContext()->setContextProperty("engine", &engine); + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:/Main.qml")); + view.show(); + + QObject::connect((QObject *) view.engine(), SIGNAL(quit()), &app, SLOT(quit())); + + app.exec(); +} + +#include "maskmaker.moc" diff --git a/shapes/tools/maskmaker/maskmaker.pro b/shapes/tools/maskmaker/maskmaker.pro new file mode 100644 index 0000000..f3a98c0 --- /dev/null +++ b/shapes/tools/maskmaker/maskmaker.pro @@ -0,0 +1,9 @@ +TARGET = maskmaker +QT += quick +CONFIG -= app_bundle +SOURCES += maskmaker.cpp +RESOURCES += maskmaker.qrc + +target.path = $$[QT_INSTALL_BINS] +INSTALLS = target + diff --git a/shapes/tools/maskmaker/maskmaker.qrc b/shapes/tools/maskmaker/maskmaker.qrc new file mode 100644 index 0000000..730d5b5 --- /dev/null +++ b/shapes/tools/maskmaker/maskmaker.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/"> + <file>Main.qml</file> + <file>Checkers.qml</file> + </qresource> +</RCC> |