diff options
Diffstat (limited to 'src/quick/scenegraph/util')
25 files changed, 4789 insertions, 0 deletions
diff --git a/src/quick/scenegraph/util/qsgareaallocator.cpp b/src/quick/scenegraph/util/qsgareaallocator.cpp new file mode 100644 index 0000000000..c5171f1c93 --- /dev/null +++ b/src/quick/scenegraph/util/qsgareaallocator.cpp @@ -0,0 +1,290 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgareaallocator_p.h" + +#include <QtCore/qglobal.h> +#include <QtCore/qrect.h> +#include <QtCore/qpoint.h> + +QT_BEGIN_NAMESPACE + +namespace +{ + enum SplitType + { + VerticalSplit, + HorizontalSplit + }; + + static const int maxMargin = 2; +} + +struct QSGAreaAllocatorNode +{ + QSGAreaAllocatorNode(QSGAreaAllocatorNode *parent); + ~QSGAreaAllocatorNode(); + inline bool isLeaf(); + + QSGAreaAllocatorNode *parent; + QSGAreaAllocatorNode *left; + QSGAreaAllocatorNode *right; + int split; // only valid for inner nodes. + SplitType splitType; + bool isOccupied; // only valid for leaf nodes. +}; + +QSGAreaAllocatorNode::QSGAreaAllocatorNode(QSGAreaAllocatorNode *parent) + : parent(parent) + , left(0) + , right(0) + , isOccupied(false) +{ +} + +QSGAreaAllocatorNode::~QSGAreaAllocatorNode() +{ + delete left; + delete right; +} + +bool QSGAreaAllocatorNode::isLeaf() +{ + Q_ASSERT((left != 0) == (right != 0)); + return !left; +} + + +QSGAreaAllocator::QSGAreaAllocator(const QSize &size) : m_size(size) +{ + m_root = new QSGAreaAllocatorNode(0); +} + +QSGAreaAllocator::~QSGAreaAllocator() +{ + delete m_root; +} + +QRect QSGAreaAllocator::allocate(const QSize &size) +{ + QPoint point; + bool result = allocateInNode(size, point, QRect(QPoint(0, 0), m_size), m_root); + return result ? QRect(point, size) : QRect(); +} + +bool QSGAreaAllocator::deallocate(const QRect &rect) +{ + return deallocateInNode(rect.topLeft(), m_root); +} + +bool QSGAreaAllocator::allocateInNode(const QSize &size, QPoint &result, const QRect ¤tRect, QSGAreaAllocatorNode *node) +{ + if (size.width() > currentRect.width() || size.height() > currentRect.height()) + return false; + + if (node->isLeaf()) { + if (node->isOccupied) + return false; + if (size.width() + maxMargin >= currentRect.width() && size.height() + maxMargin >= currentRect.height()) { + //Snug fit, occupy entire rectangle. + node->isOccupied = true; + result = currentRect.topLeft(); + return true; + } + // TODO: Reuse nodes. + // Split node. + node->left = new QSGAreaAllocatorNode(node); + node->right = new QSGAreaAllocatorNode(node); + QRect splitRect = currentRect; + if ((currentRect.width() - size.width()) * currentRect.height() < (currentRect.height() - size.height()) * currentRect.width()) { + node->splitType = HorizontalSplit; + node->split = currentRect.top() + size.height(); + splitRect.setHeight(size.height()); + } else { + node->splitType = VerticalSplit; + node->split = currentRect.left() + size.width(); + splitRect.setWidth(size.width()); + } + return allocateInNode(size, result, splitRect, node->left); + } else { + // TODO: avoid unnecessary recursion. + // has been split. + QRect leftRect = currentRect; + QRect rightRect = currentRect; + if (node->splitType == HorizontalSplit) { + leftRect.setHeight(node->split - leftRect.top()); + rightRect.setTop(node->split); + } else { + leftRect.setWidth(node->split - leftRect.left()); + rightRect.setLeft(node->split); + } + if (allocateInNode(size, result, leftRect, node->left)) + return true; + if (allocateInNode(size, result, rightRect, node->right)) + return true; + return false; + } +} + +bool QSGAreaAllocator::deallocateInNode(const QPoint &pos, QSGAreaAllocatorNode *node) +{ + while (!node->isLeaf()) { + // has been split. + int cmp = node->splitType == HorizontalSplit ? pos.y() : pos.x(); + node = cmp < node->split ? node->left : node->right; + } + if (!node->isOccupied) + return false; + node->isOccupied = false; + mergeNodeWithNeighbors(node); + return true; +} + +void QSGAreaAllocator::mergeNodeWithNeighbors(QSGAreaAllocatorNode *node) +{ + bool done = false; + QSGAreaAllocatorNode *parent = 0; + QSGAreaAllocatorNode *current = 0; + QSGAreaAllocatorNode *sibling; + while (!done) { + Q_ASSERT(node->isLeaf()); + Q_ASSERT(!node->isOccupied); + if (node->parent == 0) + return; // No neighbours. + + SplitType splitType = SplitType(node->parent->splitType); + done = true; + + /* Special case. Might be faster than going through the general code path. + // Merge with sibling. + parent = node->parent; + sibling = (node == parent->left ? parent->right : parent->left); + if (sibling->isLeaf() && !sibling->isOccupied) { + Q_ASSERT(!sibling->right); + node = parent; + parent->isOccupied = false; + delete parent->left; + delete parent->right; + parent->left = parent->right = 0; + done = false; + continue; + } + */ + + // Merge with left neighbour. + current = node; + parent = current->parent; + while (parent && current == parent->left && parent->splitType == splitType) { + current = parent; + parent = parent->parent; + } + + if (parent && parent->splitType == splitType) { + Q_ASSERT(current == parent->right); + Q_ASSERT(parent->left); + + QSGAreaAllocatorNode *neighbor = parent->left; + while (neighbor->right && neighbor->splitType == splitType) + neighbor = neighbor->right; + + if (neighbor->isLeaf() && neighbor->parent->splitType == splitType && !neighbor->isOccupied) { + // Left neighbour can be merged. + parent->split = neighbor->parent->split; + + parent = neighbor->parent; + sibling = neighbor == parent->left ? parent->right : parent->left; + QSGAreaAllocatorNode **nodeRef = &m_root; + if (parent->parent) { + if (parent == parent->parent->left) + nodeRef = &parent->parent->left; + else + nodeRef = &parent->parent->right; + } + sibling->parent = parent->parent; + *nodeRef = sibling; + parent->left = parent->right = 0; + delete parent; + delete neighbor; + done = false; + } + } + + // Merge with right neighbour. + current = node; + parent = current->parent; + while (parent && current == parent->right && parent->splitType == splitType) { + current = parent; + parent = parent->parent; + } + + if (parent && parent->splitType == splitType) { + Q_ASSERT(current == parent->left); + Q_ASSERT(parent->right); + + QSGAreaAllocatorNode *neighbor = parent->right; + while (neighbor->left && neighbor->splitType == splitType) + neighbor = neighbor->left; + + if (neighbor->isLeaf() && neighbor->parent->splitType == splitType && !neighbor->isOccupied) { + // Right neighbour can be merged. + parent->split = neighbor->parent->split; + + parent = neighbor->parent; + sibling = neighbor == parent->left ? parent->right : parent->left; + QSGAreaAllocatorNode **nodeRef = &m_root; + if (parent->parent) { + if (parent == parent->parent->left) + nodeRef = &parent->parent->left; + else + nodeRef = &parent->parent->right; + } + sibling->parent = parent->parent; + *nodeRef = sibling; + parent->left = parent->right = 0; + delete parent; + delete neighbor; + done = false; + } + } + } // end while(!done) +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgareaallocator_p.h b/src/quick/scenegraph/util/qsgareaallocator_p.h new file mode 100644 index 0000000000..be26046865 --- /dev/null +++ b/src/quick/scenegraph/util/qsgareaallocator_p.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AREAALLOCATOR_H +#define AREAALLOCATOR_H + +#include <QtQuick/qtquickglobal.h> +#include <QtCore/qsize.h> + +QT_BEGIN_NAMESPACE + +class QRect; +class QPoint; +struct QSGAreaAllocatorNode; +class Q_QUICK_EXPORT QSGAreaAllocator +{ +public: + QSGAreaAllocator(const QSize &size); + ~QSGAreaAllocator(); + + QRect allocate(const QSize &size); + bool deallocate(const QRect &rect); + bool isEmpty() const { return m_root == 0; } + QSize size() const { return m_size; } +private: + bool allocateInNode(const QSize &size, QPoint &result, const QRect ¤tRect, QSGAreaAllocatorNode *node); + bool deallocateInNode(const QPoint &pos, QSGAreaAllocatorNode *node); + void mergeNodeWithNeighbors(QSGAreaAllocatorNode *node); + + QSGAreaAllocatorNode *m_root; + QSize m_size; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil.cpp b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp new file mode 100644 index 0000000000..d1b0445ee0 --- /dev/null +++ b/src/quick/scenegraph/util/qsgdistancefieldutil.cpp @@ -0,0 +1,805 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgdistancefieldutil_p.h" + +#include <qmath.h> +#include <private/qsgpathsimplifier_p.h> +#include <private/qsgadaptationlayer_p.h> +#include <QtGui/private/qopenglengineshadersource_p.h> +#include <QtQuick/private/qsgcontext_p.h> + +QT_BEGIN_NAMESPACE + +static float defaultThresholdFunc(float glyphScale) +{ + static float base = qgetenv("QT_DF_BASE").isEmpty() ? 0.5f : qgetenv("QT_DF_BASE").toFloat(); + static float baseDev = qgetenv("QT_DF_BASEDEVIATION").isEmpty() ? 0.065f : qgetenv("QT_DF_BASEDEVIATION").toFloat(); + static float devScaleMin = qgetenv("QT_DF_SCALEFORMAXDEV").isEmpty() ? 0.15f : qgetenv("QT_DF_SCALEFORMAXDEV").toFloat(); + static float devScaleMax = qgetenv("QT_DF_SCALEFORNODEV").isEmpty() ? 0.3f : qgetenv("QT_DF_SCALEFORNODEV").toFloat(); + return base - ((qBound(devScaleMin, glyphScale, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev); +} + +static float defaultAntialiasingSpreadFunc(float glyphScale) +{ + static float range = qgetenv("QT_DF_RANGE").isEmpty() ? 0.06f : qgetenv("QT_DF_RANGE").toFloat(); + return range / glyphScale; +} + +namespace +{ + enum FillHDir + { + LeftToRight, + RightToLeft + }; + + enum FillVDir + { + TopDown, + BottomUp + }; + + enum FillClip + { + NoClip, + Clip + }; +} + +template <FillClip clip, FillHDir dir> +inline void fillLine(qint32 *, int, int, int, qint32, qint32) +{ +} + +template <> +inline void fillLine<Clip, LeftToRight>(qint32 *line, int width, int lx, int rx, qint32 d, qint32 dd) +{ + int fromX = qMax(0, lx >> 8); + int toX = qMin(width, rx >> 8); + int x = toX - fromX; + if (x <= 0) + return; + qint32 val = d + (((fromX << 8) + 0xff - lx) * dd >> 8); + line += fromX; + do { + *line = abs(val) < abs(*line) ? val : *line; + val += dd; + ++line; + } while (--x); +} + +template <> +inline void fillLine<Clip, RightToLeft>(qint32 *line, int width, int lx, int rx, qint32 d, qint32 dd) +{ + int fromX = qMax(0, lx >> 8); + int toX = qMin(width, rx >> 8); + int x = toX - fromX; + if (x <= 0) + return; + qint32 val = d + (((toX << 8) + 0xff - rx) * dd >> 8); + line += toX; + do { + val -= dd; + --line; + *line = abs(val) < abs(*line) ? val : *line; + } while (--x); +} + +template <> +inline void fillLine<NoClip, LeftToRight>(qint32 *line, int, int lx, int rx, qint32 d, qint32 dd) +{ + int fromX = lx >> 8; + int toX = rx >> 8; + int x = toX - fromX; + if (x <= 0) + return; + qint32 val = d + ((~lx & 0xff) * dd >> 8); + line += fromX; + do { + *line = abs(val) < abs(*line) ? val : *line; + val += dd; + ++line; + } while (--x); +} + +template <> +inline void fillLine<NoClip, RightToLeft>(qint32 *line, int, int lx, int rx, qint32 d, qint32 dd) +{ + int fromX = lx >> 8; + int toX = rx >> 8; + int x = toX - fromX; + if (x <= 0) + return; + qint32 val = d + ((~rx & 0xff) * dd >> 8); + line += toX; + do { + val -= dd; + --line; + *line = abs(val) < abs(*line) ? val : *line; + } while (--x); +} + +template <FillClip clip, FillVDir vDir, FillHDir hDir> +inline void fillLines(qint32 *bits, int width, int height, int upperY, int lowerY, + int &lx, int ldx, int &rx, int rdx, qint32 &d, qint32 ddy, qint32 ddx) +{ + Q_UNUSED(height); + Q_ASSERT(upperY < lowerY); + int y = lowerY - upperY; + if (vDir == TopDown) { + qint32 *line = bits + upperY * width; + do { + fillLine<clip, hDir>(line, width, lx, rx, d, ddx); + lx += ldx; + d += ddy; + rx += rdx; + line += width; + } while (--y); + } else { + qint32 *line = bits + lowerY * width; + do { + lx -= ldx; + d -= ddy; + rx -= rdx; + line -= width; + fillLine<clip, hDir>(line, width, lx, rx, d, ddx); + } while (--y); + } +} + +template <FillClip clip> +void drawTriangle(qint32 *bits, int width, int height, const QPoint *center, + const QPoint *v1, const QPoint *v2, qint32 value) +{ + const int y1 = clip == Clip ? qBound(0, v1->y() >> 8, height) : v1->y() >> 8; + const int y2 = clip == Clip ? qBound(0, v2->y() >> 8, height) : v2->y() >> 8; + const int yC = clip == Clip ? qBound(0, center->y() >> 8, height) : center->y() >> 8; + + const int v1Frac = clip == Clip ? (y1 << 8) + 0xff - v1->y() : ~v2->y() & 0xff; + const int v2Frac = clip == Clip ? (y2 << 8) + 0xff - v2->y() : ~v1->y() & 0xff; + const int centerFrac = clip == Clip ? (yC << 8) + 0xff - center->y() : ~center->y() & 0xff; + + int dx1 = 0, x1 = 0, dx2 = 0, x2 = 0; + qint32 dd1, d1, dd2, d2; + if (v1->y() != center->y()) { + dx1 = ((v1->x() - center->x()) << 8) / (v1->y() - center->y()); + x1 = center->x() + centerFrac * (v1->x() - center->x()) / (v1->y() - center->y()); + } + if (v2->y() != center->y()) { + dx2 = ((v2->x() - center->x()) << 8) / (v2->y() - center->y()); + x2 = center->x() + centerFrac * (v2->x() - center->x()) / (v2->y() - center->y()); + } + + const qint32 div = (v2->x() - center->x()) * (v1->y() - center->y()) + - (v2->y() - center->y()) * (v1->x() - center->x()); + const qint32 dd = div ? qint32((qint64(value * (v1->y() - v2->y())) << 8) / div) : 0; + + if (y2 < yC) { + if (y1 < yC) { + // Center at the bottom. + if (y2 < y1) { + // y2 < y1 < yC + // Long right edge. + d1 = centerFrac * value / (v1->y() - center->y()); + dd1 = ((value << 8) / (v1->y() - center->y())); + fillLines<clip, BottomUp, LeftToRight>(bits, width, height, y1, yC, x1, dx1, + x2, dx2, d1, dd1, dd); + dx1 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y()); + x1 = v1->x() + v1Frac * (v1->x() - v2->x()) / (v1->y() - v2->y()); + fillLines<clip, BottomUp, LeftToRight>(bits, width, height, y2, y1, x1, dx1, + x2, dx2, value, 0, dd); + } else { + // y1 <= y2 < yC + // Long left edge. + d2 = centerFrac * value / (v2->y() - center->y()); + dd2 = ((value << 8) / (v2->y() - center->y())); + fillLines<clip, BottomUp, RightToLeft>(bits, width, height, y2, yC, x1, dx1, + x2, dx2, d2, dd2, dd); + if (y1 != y2) { + dx2 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y()); + x2 = v2->x() + v2Frac * (v1->x() - v2->x()) / (v1->y() - v2->y()); + fillLines<clip, BottomUp, RightToLeft>(bits, width, height, y1, y2, x1, dx1, + x2, dx2, value, 0, dd); + } + } + } else { + // y2 < yC <= y1 + // Center to the right. + int dx = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y()); + int xUp, xDn; + xUp = xDn = v2->x() + (clip == Clip ? (yC << 8) + 0xff - v2->y() + : (center->y() | 0xff) - v2->y()) + * (v1->x() - v2->x()) / (v1->y() - v2->y()); + fillLines<clip, BottomUp, LeftToRight>(bits, width, height, y2, yC, xUp, dx, + x2, dx2, value, 0, dd); + if (yC != y1) + fillLines<clip, TopDown, LeftToRight>(bits, width, height, yC, y1, xDn, dx, + x1, dx1, value, 0, dd); + } + } else { + if (y1 < yC) { + // y1 < yC <= y2 + // Center to the left. + int dx = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y()); + int xUp, xDn; + xUp = xDn = v1->x() + (clip == Clip ? (yC << 8) + 0xff - v1->y() + : (center->y() | 0xff) - v1->y()) + * (v1->x() - v2->x()) / (v1->y() - v2->y()); + fillLines<clip, BottomUp, RightToLeft>(bits, width, height, y1, yC, x1, dx1, + xUp, dx, value, 0, dd); + if (yC != y2) + fillLines<clip, TopDown, RightToLeft>(bits, width, height, yC, y2, x2, dx2, + xDn, dx, value, 0, dd); + } else { + // Center at the top. + if (y2 < y1) { + // yC <= y2 < y1 + // Long right edge. + if (yC != y2) { + d2 = centerFrac * value / (v2->y() - center->y()); + dd2 = ((value << 8) / (v2->y() - center->y())); + fillLines<clip, TopDown, LeftToRight>(bits, width, height, yC, y2, x2, dx2, + x1, dx1, d2, dd2, dd); + } + dx2 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y()); + x2 = v2->x() + v2Frac * (v1->x() - v2->x()) / (v1->y() - v2->y()); + fillLines<clip, TopDown, LeftToRight>(bits, width, height, y2, y1, x2, dx2, + x1, dx1, value, 0, dd); + } else { + // Long left edge. + // yC <= y1 <= y2 + if (yC != y1) { + d1 = centerFrac * value / (v1->y() - center->y()); + dd1 = ((value << 8) / (v1->y() - center->y())); + fillLines<clip, TopDown, RightToLeft>(bits, width, height, yC, y1, x2, dx2, + x1, dx1, d1, dd1, dd); + } + if (y1 != y2) { + dx1 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y()); + x1 = v1->x() + v1Frac * (v1->x() - v2->x()) / (v1->y() - v2->y()); + fillLines<clip, TopDown, RightToLeft>(bits, width, height, y1, y2, x2, dx2, + x1, dx1, value, 0, dd); + } + } + } + } +} + +template <FillClip clip> +void drawRectangle(qint32 *bits, int width, int height, + const QPoint *int1, const QPoint *center1, const QPoint *ext1, + const QPoint *int2, const QPoint *center2, const QPoint *ext2, + qint32 extValue) +{ + if (center1->y() > center2->y()) { + qSwap(center1, center2); + qSwap(int1, ext2); + qSwap(ext1, int2); + extValue = -extValue; + } + + Q_ASSERT(ext1->x() - center1->x() == center1->x() - int1->x()); + Q_ASSERT(ext1->y() - center1->y() == center1->y() - int1->y()); + Q_ASSERT(ext2->x() - center2->x() == center2->x() - int2->x()); + Q_ASSERT(ext2->y() - center2->y() == center2->y() - int2->y()); + + const int yc1 = clip == Clip ? qBound(0, center1->y() >> 8, height) : center1->y() >> 8; + const int yc2 = clip == Clip ? qBound(0, center2->y() >> 8, height) : center2->y() >> 8; + const int yi1 = clip == Clip ? qBound(0, int1->y() >> 8, height) : int1->y() >> 8; + const int yi2 = clip == Clip ? qBound(0, int2->y() >> 8, height) : int2->y() >> 8; + const int ye1 = clip == Clip ? qBound(0, ext1->y() >> 8, height) : ext1->y() >> 8; + const int ye2 = clip == Clip ? qBound(0, ext2->y() >> 8, height) : ext2->y() >> 8; + + const int center1Frac = clip == Clip ? (yc1 << 8) + 0xff - center1->y() : ~center1->y() & 0xff; + const int center2Frac = clip == Clip ? (yc2 << 8) + 0xff - center2->y() : ~center2->y() & 0xff; + const int int1Frac = clip == Clip ? (yi1 << 8) + 0xff - int1->y() : ~int1->y() & 0xff; + const int ext1Frac = clip == Clip ? (ye1 << 8) + 0xff - ext1->y() : ~ext1->y() & 0xff; + + int dxC = 0, dxE = 0; // cap slope, edge slope + qint32 ddC = 0; + if (ext1->y() != int1->y()) { + dxC = ((ext1->x() - int1->x()) << 8) / (ext1->y() - int1->y()); + ddC = (extValue << 9) / (ext1->y() - int1->y()); + } + if (ext1->y() != ext2->y()) + dxE = ((ext1->x() - ext2->x()) << 8) / (ext1->y() - ext2->y()); + + const qint32 div = (ext1->x() - int1->x()) * (ext2->y() - int1->y()) + - (ext1->y() - int1->y()) * (ext2->x() - int1->x()); + const qint32 dd = div ? qint32((qint64(extValue * (ext2->y() - ext1->y())) << 9) / div) : 0; + + int xe1, xe2, xc1, xc2; + qint32 d; + + qint32 intValue = -extValue; + + if (center2->x() < center1->x()) { + // Leaning to the right. '/' + if (int1->y() < ext2->y()) { + // Mostly vertical. + Q_ASSERT(ext1->y() != ext2->y()); + xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y()); + xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y()); + if (ye1 != yi1) { + xc2 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y()); + xc2 += (ye1 - yc1) * dxC; + fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye1, yi1, xe1, dxE, + xc2, dxC, extValue, 0, dd); + } + if (yi1 != ye2) + fillLines<clip, TopDown, LeftToRight>(bits, width, height, yi1, ye2, xe1, dxE, + xe2, dxE, extValue, 0, dd); + if (ye2 != yi2) { + xc1 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y()); + xc1 += (ye2 - yc2) * dxC; + fillLines<clip, TopDown, RightToLeft>(bits, width, height, ye2, yi2, xc1, dxC, + xe2, dxE, intValue, 0, dd); + } + } else { + // Mostly horizontal. + Q_ASSERT(ext1->y() != int1->y()); + xc1 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y()); + xc2 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y()); + xc1 += (ye2 - yc2) * dxC; + xc2 += (ye1 - yc1) * dxC; + if (ye1 != ye2) { + xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y()); + fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye1, ye2, xe1, dxE, + xc2, dxC, extValue, 0, dd); + } + if (ye2 != yi1) { + d = (clip == Clip ? (ye2 << 8) + 0xff - center2->y() + : (ext2->y() | 0xff) - center2->y()) + * 2 * extValue / (ext1->y() - int1->y()); + fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye2, yi1, xc1, dxC, + xc2, dxC, d, ddC, dd); + } + if (yi1 != yi2) { + xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y()); + fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi1, yi2, xc1, dxC, + xe2, dxE, intValue, 0, dd); + } + } + } else { + // Leaning to the left. '\' + if (ext1->y() < int2->y()) { + // Mostly vertical. + Q_ASSERT(ext1->y() != ext2->y()); + xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y()); + xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y()); + if (yi1 != ye1) { + xc1 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y()); + xc1 += (yi1 - yc1) * dxC; + fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi1, ye1, xc1, dxC, + xe2, dxE, intValue, 0, dd); + } + if (ye1 != yi2) + fillLines<clip, TopDown, RightToLeft>(bits, width, height, ye1, yi2, xe1, dxE, + xe2, dxE, intValue, 0, dd); + if (yi2 != ye2) { + xc2 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y()); + xc2 += (yi2 - yc2) * dxC; + fillLines<clip, TopDown, LeftToRight>(bits, width, height, yi2, ye2, xe1, dxE, + xc2, dxC, extValue, 0, dd); + } + } else { + // Mostly horizontal. + Q_ASSERT(ext1->y() != int1->y()); + xc1 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y()); + xc2 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y()); + xc1 += (yi1 - yc1) * dxC; + xc2 += (yi2 - yc2) * dxC; + if (yi1 != yi2) { + xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y()); + fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi1, yi2, xc1, dxC, + xe2, dxE, intValue, 0, dd); + } + if (yi2 != ye1) { + d = (clip == Clip ? (yi2 << 8) + 0xff - center2->y() + : (int2->y() | 0xff) - center2->y()) + * 2 * extValue / (ext1->y() - int1->y()); + fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi2, ye1, xc1, dxC, + xc2, dxC, d, ddC, dd); + } + if (ye1 != ye2) { + xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y()); + fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye1, ye2, xe1, dxE, + xc2, dxC, extValue, 0, dd); + } + } + } +} + +static void drawPolygons(qint32 *bits, int width, int height, const QPoint *vertices, + const quint32 *indices, int indexCount, qint32 value) +{ + Q_ASSERT(indexCount != 0); + Q_ASSERT(height <= 128); + QVarLengthArray<quint8, 16> scans[128]; + int first = 0; + for (int i = 1; i < indexCount; ++i) { + quint32 idx1 = indices[i - 1]; + quint32 idx2 = indices[i]; + Q_ASSERT(idx1 != quint32(-1)); + if (idx2 == quint32(-1)) { + idx2 = indices[first]; + Q_ASSERT(idx2 != quint32(-1)); + first = ++i; + } + const QPoint *v1 = &vertices[idx1]; + const QPoint *v2 = &vertices[idx2]; + if (v2->y() < v1->y()) + qSwap(v1, v2); + int fromY = qMax(0, v1->y() >> 8); + int toY = qMin(height, v2->y() >> 8); + if (fromY >= toY) + continue; + int dx = ((v2->x() - v1->x()) << 8) / (v2->y() - v1->y()); + int x = v1->x() + ((fromY << 8) + 0xff - v1->y()) * (v2->x() - v1->x()) / (v2->y() - v1->y()); + for (int y = fromY; y < toY; ++y) { + quint32 c = quint32(x >> 8); + if (c < quint32(width)) + scans[y].append(quint8(c)); + x += dx; + } + } + for (int i = 0; i < height; ++i) { + quint8 *scanline = scans[i].data(); + int size = scans[i].size(); + for (int j = 1; j < size; ++j) { + int k = j; + quint8 value = scanline[k]; + for (; k != 0 && value < scanline[k - 1]; --k) + scanline[k] = scanline[k - 1]; + scanline[k] = value; + } + qint32 *line = bits + i * width; + int j = 0; + for (; j + 1 < size; j += 2) { + for (quint8 x = scanline[j]; x < scanline[j + 1]; ++x) + line[x] = value; + } + if (j < size) { + for (int x = scanline[j]; x < width; ++x) + line[x] = value; + } + } +} + +static QImage makeDistanceField(int imgSize, const QPainterPath &path, int dfScale, int offs) +{ + QImage image(imgSize, imgSize, QImage::Format_Indexed8); + + if (path.isEmpty()) { + image.fill(0); + return image; + } + + QTransform transform; + transform.translate(offs, offs); + transform.scale(qreal(1) / dfScale, qreal(1) / dfScale); + + QDataBuffer<quint32> pathIndices(0); + QDataBuffer<QPoint> pathVertices(0); + qSimplifyPath(path, pathVertices, pathIndices, transform); + + const qint32 interiorColor = -0x7f80; // 8:8 signed format, -127.5 + const qint32 exteriorColor = 0x7f80; // 8:8 signed format, 127.5 + + QScopedArrayPointer<qint32> bits(new qint32[imgSize * imgSize]); + for (int i = 0; i < imgSize * imgSize; ++i) + bits[i] = exteriorColor; + + const qreal angleStep = qreal(15 * 3.141592653589793238 / 180); + const QPoint rotation(qRound(cos(angleStep) * 0x4000), + qRound(sin(angleStep) * 0x4000)); // 2:14 signed + + const quint32 *indices = pathIndices.data(); + QVarLengthArray<QPoint> normals; + QVarLengthArray<QPoint> vertices; + QVarLengthArray<bool> isConvex; + QVarLengthArray<bool> needsClipping; + + drawPolygons(bits.data(), imgSize, imgSize, pathVertices.data(), indices, pathIndices.size(), + interiorColor); + + int index = 0; + + while (index < pathIndices.size()) { + normals.clear(); + vertices.clear(); + needsClipping.clear(); + + // Find end of polygon. + int end = index; + while (indices[end] != quint32(-1)) + ++end; + + // Calculate vertex normals. + for (int next = index, prev = end - 1; next < end; prev = next++) { + quint32 fromVertexIndex = indices[prev]; + quint32 toVertexIndex = indices[next]; + + const QPoint &from = pathVertices.at(fromVertexIndex); + const QPoint &to = pathVertices.at(toVertexIndex); + + QPoint n(to.y() - from.y(), from.x() - to.x()); + if (n.x() == 0 && n.y() == 0) + continue; + int scale = qRound((offs << 16) / sqrt(qreal(n.x() * n.x() + n.y() * n.y()))); // 8:16 + n.rx() = n.x() * scale >> 8; + n.ry() = n.y() * scale >> 8; + normals.append(n); + QPoint v(to.x() + 0x7f, to.y() + 0x7f); + vertices.append(v); + needsClipping.append((to.x() < offs << 8) || (to.x() >= (imgSize - offs) << 8) + || (to.y() < offs << 8) || (to.y() >= (imgSize - offs) << 8)); + } + + isConvex.resize(normals.count()); + for (int next = 0, prev = normals.count() - 1; next < normals.count(); prev = next++) { + isConvex[prev] = normals.at(prev).x() * normals.at(next).y() + - normals.at(prev).y() * normals.at(next).x() < 0; + } + + // Draw quads. + for (int next = 0, prev = normals.count() - 1; next < normals.count(); prev = next++) { + QPoint n = normals.at(next); + QPoint intPrev = vertices.at(prev); + QPoint extPrev = vertices.at(prev); + QPoint intNext = vertices.at(next); + QPoint extNext = vertices.at(next); + + extPrev.rx() -= n.x(); + extPrev.ry() -= n.y(); + intPrev.rx() += n.x(); + intPrev.ry() += n.y(); + extNext.rx() -= n.x(); + extNext.ry() -= n.y(); + intNext.rx() += n.x(); + intNext.ry() += n.y(); + + if (needsClipping[prev] || needsClipping[next]) { + drawRectangle<Clip>(bits.data(), imgSize, imgSize, + &intPrev, &vertices.at(prev), &extPrev, + &intNext, &vertices.at(next), &extNext, + exteriorColor); + } else { + drawRectangle<NoClip>(bits.data(), imgSize, imgSize, + &intPrev, &vertices.at(prev), &extPrev, + &intNext, &vertices.at(next), &extNext, + exteriorColor); + } + + if (isConvex.at(prev)) { + QPoint p = extPrev; + if (needsClipping[prev]) { + for (;;) { + QPoint rn((n.x() * rotation.x() - n.y() * rotation.y()) >> 14, + (n.y() * rotation.x() + n.x() * rotation.y()) >> 14); + n = rn; + if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() <= 0) { + p.rx() = vertices.at(prev).x() - normals.at(prev).x(); + p.ry() = vertices.at(prev).y() - normals.at(prev).y(); + drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev), + &extPrev, &p, exteriorColor); + break; + } + + p.rx() = vertices.at(prev).x() - n.x(); + p.ry() = vertices.at(prev).y() - n.y(); + drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev), + &extPrev, &p, exteriorColor); + extPrev = p; + } + } else { + for (;;) { + QPoint rn((n.x() * rotation.x() - n.y() * rotation.y()) >> 14, + (n.y() * rotation.x() + n.x() * rotation.y()) >> 14); + n = rn; + if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() <= 0) { + p.rx() = vertices.at(prev).x() - normals.at(prev).x(); + p.ry() = vertices.at(prev).y() - normals.at(prev).y(); + drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev), + &extPrev, &p, exteriorColor); + break; + } + + p.rx() = vertices.at(prev).x() - n.x(); + p.ry() = vertices.at(prev).y() - n.y(); + drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev), + &extPrev, &p, exteriorColor); + extPrev = p; + } + } + } else { + QPoint p = intPrev; + if (needsClipping[prev]) { + for (;;) { + QPoint rn((n.x() * rotation.x() + n.y() * rotation.y()) >> 14, + (n.y() * rotation.x() - n.x() * rotation.y()) >> 14); + n = rn; + if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() >= 0) { + p.rx() = vertices.at(prev).x() + normals.at(prev).x(); + p.ry() = vertices.at(prev).y() + normals.at(prev).y(); + drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev), + &p, &intPrev, interiorColor); + break; + } + + p.rx() = vertices.at(prev).x() + n.x(); + p.ry() = vertices.at(prev).y() + n.y(); + drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev), + &p, &intPrev, interiorColor); + intPrev = p; + } + } else { + for (;;) { + QPoint rn((n.x() * rotation.x() + n.y() * rotation.y()) >> 14, + (n.y() * rotation.x() - n.x() * rotation.y()) >> 14); + n = rn; + if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() >= 0) { + p.rx() = vertices.at(prev).x() + normals.at(prev).x(); + p.ry() = vertices.at(prev).y() + normals.at(prev).y(); + drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev), + &p, &intPrev, interiorColor); + break; + } + + p.rx() = vertices.at(prev).x() + n.x(); + p.ry() = vertices.at(prev).y() + n.y(); + drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev), + &p, &intPrev, interiorColor); + intPrev = p; + } + } + } + } + + index = end + 1; + } + + const qint32 *inLine = bits.data(); + uchar *outLine = image.bits(); + int padding = image.bytesPerLine() - image.width(); + for (int y = 0; y < imgSize; ++y) { + for (int x = 0; x < imgSize; ++x, ++inLine, ++outLine) + *outLine = uchar((0x7f80 - *inLine) >> 8); + outLine += padding; + } + + return image; +} + +bool qt_fontHasNarrowOutlines(const QRawFont &f) +{ + QRawFont font = f; + font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE); + Q_ASSERT(font.isValid()); + + QVector<quint32> glyphIndices = font.glyphIndexesForString(QLatin1String("O")); + if (glyphIndices.size() < 1) + return false; + + QImage im = font.alphaMapForGlyph(glyphIndices.at(0), QRawFont::PixelAntialiasing); + if (im.isNull()) + return false; + + int minHThick = 999; + int minVThick = 999; + + int thick = 0; + bool in = false; + int y = (im.height() + 1) / 2; + for (int x = 0; x < im.width(); ++x) { + int a = qAlpha(im.pixel(x, y)); + if (a > 127) { + in = true; + ++thick; + } else if (in) { + in = false; + minHThick = qMin(minHThick, thick); + thick = 0; + } + } + + thick = 0; + in = false; + int x = (im.width() + 1) / 2; + for (int y = 0; y < im.height(); ++y) { + int a = qAlpha(im.pixel(x, y)); + if (a > 127) { + in = true; + ++thick; + } else if (in) { + in = false; + minVThick = qMin(minVThick, thick); + thick = 0; + } + } + + return minHThick == 1 || minVThick == 1; +} + +QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution) +{ + QRawFont renderFont = font; + renderFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(doubleResolution) * QT_DISTANCEFIELD_SCALE(doubleResolution)); + + QPainterPath path = renderFont.pathForGlyph(glyph); + path.translate(-path.boundingRect().topLeft()); + path.setFillRule(Qt::WindingFill); + + QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE(doubleResolution), + path, + QT_DISTANCEFIELD_SCALE(doubleResolution), + QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution)); + return im; +} + +QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager(QSGContext *c) + : sgCtx(c) + , m_threshold_func(defaultThresholdFunc) + , m_antialiasingSpread_func(defaultAntialiasingSpreadFunc) +{ +#ifndef QT_OPENGL_ES + m_defaultAntialiasingMode = QSGGlyphNode::HighQualitySubPixelAntialiasing; +#else + m_defaultAntialiasingMode = QSGGlyphNode::GrayAntialiasing; +#endif +} + +QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager() +{ + qDeleteAll(m_caches.values()); +} + +QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCacheManager::cache(const QRawFont &font) +{ + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + QHash<QFontEngine *, QSGDistanceFieldGlyphCache *>::iterator cache = m_caches.find(fontD->fontEngine); + if (cache == m_caches.end()) + cache = m_caches.insert(fontD->fontEngine, sgCtx->createDistanceFieldGlyphCache(font)); + return cache.value(); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgdistancefieldutil_p.h b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h new file mode 100644 index 0000000000..bc28a4d9e1 --- /dev/null +++ b/src/quick/scenegraph/util/qsgdistancefieldutil_p.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGDISTANCEFIELDUTIL_H +#define QSGDISTANCEFIELDUTIL_H + +#include <qrawfont.h> +#include <private/qfontengine_p.h> +#include <private/qsgadaptationlayer_p.h> + +QT_BEGIN_NAMESPACE + +#define QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE 54 +#define QT_DISTANCEFIELD_DEFAULT_TILESIZE 64 +#define QT_DISTANCEFIELD_DEFAULT_SCALE 16 +#define QT_DISTANCEFIELD_DEFAULT_RADIUS 80 +#define QT_DISTANCEFIELD_HIGHGLYPHCOUNT 2000 + +#define QT_DISTANCEFIELD_BASEFONTSIZE(NarrowOutlineFont) \ + (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE * 2 : \ + QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE) +#define QT_DISTANCEFIELD_TILESIZE(NarrowOutlineFont) \ + (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_TILESIZE * 2 : \ + QT_DISTANCEFIELD_DEFAULT_TILESIZE) +#define QT_DISTANCEFIELD_SCALE(NarrowOutlineFont) \ + (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_SCALE / 2 : \ + QT_DISTANCEFIELD_DEFAULT_SCALE) +#define QT_DISTANCEFIELD_RADIUS(NarrowOutlineFont) \ + (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_RADIUS / 2 : \ + QT_DISTANCEFIELD_DEFAULT_RADIUS) + + +typedef float (*ThresholdFunc)(float glyphScale); +typedef float (*AntialiasingSpreadFunc)(float glyphScale); + +bool qt_fontHasNarrowOutlines(const QRawFont &f); +QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution); + + +class QOpenGLShaderProgram; +class QSGDistanceFieldGlyphCache; +class QSGContext; + +class Q_QUICK_EXPORT QSGDistanceFieldGlyphCacheManager +{ +public: + QSGDistanceFieldGlyphCacheManager(QSGContext *c); + ~QSGDistanceFieldGlyphCacheManager(); + + QSGDistanceFieldGlyphCache *cache(const QRawFont &font); + + QSGGlyphNode::AntialiasingMode defaultAntialiasingMode() const { return m_defaultAntialiasingMode; } + void setDefaultAntialiasingMode(QSGGlyphNode::AntialiasingMode mode) { m_defaultAntialiasingMode = mode; } + + ThresholdFunc thresholdFunc() const { return m_threshold_func; } + void setThresholdFunc(ThresholdFunc func) { m_threshold_func = func; } + + AntialiasingSpreadFunc antialiasingSpreadFunc() const { return m_antialiasingSpread_func; } + void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; } + +private: + QHash<QFontEngine *, QSGDistanceFieldGlyphCache *> m_caches; + + QSGContext *sgCtx; + + QSGGlyphNode::AntialiasingMode m_defaultAntialiasingMode; + ThresholdFunc m_threshold_func; + AntialiasingSpreadFunc m_antialiasingSpread_func; +}; + +QT_END_NAMESPACE + +#endif // QSGDISTANCEFIELDUTIL_H diff --git a/src/quick/scenegraph/util/qsgengine.cpp b/src/quick/scenegraph/util/qsgengine.cpp new file mode 100644 index 0000000000..b8c93bab8b --- /dev/null +++ b/src/quick/scenegraph/util/qsgengine.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgengine.h" + +#include <QtQuick/qquickcanvas.h> + +#include <private/qobject_p.h> +#include <QtGui/QColor> + +QT_BEGIN_NAMESPACE + +class QSGEnginePrivate : public QObjectPrivate +{ +public: + QSGEnginePrivate() + : canvas(0) + { + } + + QQuickCanvas *canvas; +}; + +/*! + \class QSGEngine + \deprecated + */ + +QSGEngine::QSGEngine(QObject *parent) : + QObject(*(new QSGEnginePrivate), parent) +{ +} + + +QSGEngine::~QSGEngine() +{ +} + + +void QSGEngine::setCanvas(QQuickCanvas *canvas) +{ + d_func()->canvas = canvas; + connect(canvas, SIGNAL(afterRendering()), this, SIGNAL(afterRendering())); + connect(canvas, SIGNAL(beforeRendering()), this, SIGNAL(beforeRendering())); +} + +void QSGEngine::setClearBeforeRendering(bool enabled) +{ + d_func()->canvas->setClearBeforeRendering(enabled); +} + +bool QSGEngine::clearBeforeRendering() const +{ + return d_func()->canvas->clearBeforeRendering(); +} + +QSGTexture *QSGEngine::createTextureFromImage(const QImage &image) const +{ + return d_func()->canvas->createTextureFromImage(image); +} + +QSGTexture *QSGEngine::createTextureFromId(uint id, const QSize &size, TextureOptions options) const +{ + return d_func()->canvas->createTextureFromId(id, size, QQuickCanvas::CreateTextureOptions((int) options)); +} + +void QSGEngine::setClearColor(const QColor &color) +{ + d_func()->canvas->setClearColor(color); +} + +QColor QSGEngine::clearColor() const +{ + return d_func()->canvas->clearColor(); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h new file mode 100644 index 0000000000..6b7ceb939f --- /dev/null +++ b/src/quick/scenegraph/util/qsgengine.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGENGINE_H +#define QSGENGINE_H + +#include <QObject> + +#include <QtQuick/qsgtexture.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QSGEnginePrivate; + +class QQuickCanvas; + +class Q_QUICK_EXPORT QSGEngine : public QObject +{ + Q_OBJECT + + Q_DECLARE_PRIVATE(QSGEngine) + +public: + + enum TextureOption { + TextureHasAlphaChannel = 0x0001, + TextureHasMipmaps = 0x0002, + TextureOwnsGLTexture = 0x0004 + }; + Q_DECLARE_FLAGS(TextureOptions, TextureOption) + + QSGTexture *createTextureFromImage(const QImage &image) const; + QSGTexture *createTextureFromId(uint id, const QSize &size, TextureOptions options = TextureOption(0)) const; + + void setClearBeforeRendering(bool enabled); + bool clearBeforeRendering() const; + + void setClearColor(const QColor &color); + QColor clearColor() const; + +Q_SIGNALS: + void beforeRendering(); + void afterRendering(); + +private: + QSGEngine(QObject *parent = 0); + ~QSGEngine(); + + friend class QSGContext; + friend class QSGContextPrivate; + friend class QQuickCanvasPrivate; + void setCanvas(QQuickCanvas *canvas); + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSGENGINE_H diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp new file mode 100644 index 0000000000..cf5c7869ea --- /dev/null +++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgflatcolormaterial.h" + +#include <qopenglshaderprogram.h> + +QT_BEGIN_NAMESPACE + +class FlatColorMaterialShader : public QSGMaterialShader +{ +public: + virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + virtual char const *const *attributeNames() const; + + static QSGMaterialType type; + +private: + virtual void initialize(); + virtual const char *vertexShader() const; + virtual const char *fragmentShader() const; + + int m_matrix_id; + int m_color_id; +}; + +QSGMaterialType FlatColorMaterialShader::type; + +void FlatColorMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) +{ + Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + + QSGFlatColorMaterial *oldMaterial = static_cast<QSGFlatColorMaterial *>(oldEffect); + QSGFlatColorMaterial *newMaterial = static_cast<QSGFlatColorMaterial *>(newEffect); + + const QColor &c = newMaterial->color(); + + if (oldMaterial == 0 || c != oldMaterial->color() || state.isOpacityDirty()) { + float opacity = state.opacity(); + QVector4D v(c.redF() * c.alphaF() * opacity, + c.greenF() * c.alphaF() * opacity, + c.blueF() * c.alphaF() * opacity, + c.alphaF() * opacity); + program()->setUniformValue(m_color_id, v); + } + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, state.combinedMatrix()); +} + +char const *const *FlatColorMaterialShader::attributeNames() const +{ + static char const *const attr[] = { "vCoord", 0 }; + return attr; +} + +void FlatColorMaterialShader::initialize() +{ + m_matrix_id = program()->uniformLocation("matrix"); + m_color_id = program()->uniformLocation("color"); +} + +const char *FlatColorMaterialShader::vertexShader() const { + return + "attribute highp vec4 vCoord; \n" + "uniform highp mat4 matrix; \n" + "void main() { \n" + " gl_Position = matrix * vCoord; \n" + "}"; +} + +const char *FlatColorMaterialShader::fragmentShader() const { + return + "uniform lowp vec4 color; \n" + "void main() { \n" + " gl_FragColor = color; \n" + "}"; +} + + + +/*! + \class QSGFlatColorMaterial + \brief The QSGFlatColorMaterial class provides a convenient way of rendering + solid colored geometry in the scene graph. + + \inmodule QtQuick + + The flat color material will fill every pixel in a geometry using + a solid color. The color can contain transparency. + + The geometry to be rendered with a flat color material requires + vertices in attribute location 0 in the QSGGeometry object to render + correctly. The QSGGeometry::defaultAttributes_Point2D() returns an attribute + set compatible with this material. + + The flat color material respects both current opacity and current matrix + when updating it's rendering state. + */ + + +/*! + Constructs a new flat color material. + + The default color is white. + */ + +QSGFlatColorMaterial::QSGFlatColorMaterial() : m_color(QColor(255, 255, 255)) +{ +} + + + +/*! + \fn QColor QSGFlatColorMaterial::color() const + + Returns this flat color material's color. + + The default color is white. + */ + + + +/*! + Sets this flat color material's color to \a color. + */ + +void QSGFlatColorMaterial::setColor(const QColor &color) +{ + m_color = color; + setFlag(Blending, m_color.alpha() != 0xff); +} + + + +/*! + \internal + */ + +QSGMaterialType *QSGFlatColorMaterial::type() const +{ + return &FlatColorMaterialShader::type; +} + + + +/*! + \internal + */ + +QSGMaterialShader *QSGFlatColorMaterial::createShader() const +{ + return new FlatColorMaterialShader; +} + + +int QSGFlatColorMaterial::compare(const QSGMaterial *other) const +{ + const QSGFlatColorMaterial *flat = static_cast<const QSGFlatColorMaterial *>(other); + return m_color.rgba() - flat->color().rgba(); + +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.h b/src/quick/scenegraph/util/qsgflatcolormaterial.h new file mode 100644 index 0000000000..d788901b8a --- /dev/null +++ b/src/quick/scenegraph/util/qsgflatcolormaterial.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FLATCOLORMATERIAL_H +#define FLATCOLORMATERIAL_H + +#include <QtQuick/qsgmaterial.h> +#include <qcolor.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGFlatColorMaterial : public QSGMaterial +{ +public: + QSGFlatColorMaterial(); + virtual QSGMaterialType *type() const; + virtual QSGMaterialShader *createShader() const; + + void setColor(const QColor &color); + const QColor &color() const { return m_color; } + + int compare(const QSGMaterial *other) const; + +private: + QColor m_color; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // FLATCOLORMATERIAL_H diff --git a/src/quick/scenegraph/util/qsgpainternode.cpp b/src/quick/scenegraph/util/qsgpainternode.cpp new file mode 100644 index 0000000000..640aab967e --- /dev/null +++ b/src/quick/scenegraph/util/qsgpainternode.cpp @@ -0,0 +1,464 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgpainternode_p.h" + +#include <QtQuick/private/qquickpainteditem_p.h> + +#include <QtQuick/private/qsgcontext_p.h> +#include <private/qopenglextensions_p.h> +#include <qopenglframebufferobject.h> +#include <qopenglfunctions.h> +#include <qopenglpaintdevice.h> +#include <qmath.h> +#include <qpainter.h> + +QT_BEGIN_NAMESPACE + +#define QT_MINIMUM_DYNAMIC_FBO_SIZE 64 + +static inline int qt_next_power_of_two(int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + ++v; + return v; +} + +QSGPainterTexture::QSGPainterTexture() + : QSGPlainTexture() +{ + +} + +void QSGPainterTexture::bind() +{ + if (m_dirty_rect.isNull()) { + QSGPlainTexture::bind(); + return; + } + + bool oldMipmapsGenerated = m_mipmaps_generated; + m_mipmaps_generated = true; + QSGPlainTexture::bind(); + m_mipmaps_generated = oldMipmapsGenerated; + + QImage subImage = m_image.copy(m_dirty_rect); + + int w = m_dirty_rect.width(); + int h = m_dirty_rect.height(); + +#ifdef QT_OPENGL_ES + glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h, + GL_RGBA, GL_UNSIGNED_BYTE, subImage.constBits()); +#else + glTexSubImage2D(GL_TEXTURE_2D, 0, m_dirty_rect.x(), m_dirty_rect.y(), w, h, + GL_BGRA, GL_UNSIGNED_BYTE, subImage.constBits()); +#endif + + if (m_has_mipmaps && !m_mipmaps_generated) { + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D); + m_mipmaps_generated = true; + } + + m_dirty_texture = false; + m_dirty_bind_options = false; + + m_dirty_rect = QRect(); +} + +QSGPainterNode::QSGPainterNode(QQuickPaintedItem *item) + : QSGGeometryNode() + , m_preferredRenderTarget(QQuickPaintedItem::Image) + , m_actualRenderTarget(QQuickPaintedItem::Image) + , m_item(item) + , m_fbo(0) + , m_multisampledFbo(0) + , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) + , m_texture(0) + , m_gl_device(0) + , m_size(1, 1) + , m_dirtyContents(false) + , m_opaquePainting(false) + , m_linear_filtering(false) + , m_mipmapping(false) + , m_smoothPainting(false) + , m_extensionsChecked(false) + , m_multisamplingSupported(false) + , m_fastFBOResizing(false) + , m_fillColor(Qt::transparent) + , m_contentsScale(1.0) + , m_dirtyGeometry(false) + , m_dirtyRenderTarget(false) + , m_dirtyTexture(false) +{ + m_context = static_cast<QQuickPaintedItemPrivate *>(QObjectPrivate::get(item))->sceneGraphContext(); + + setMaterial(&m_materialO); + setOpaqueMaterial(&m_material); + setGeometry(&m_geometry); +} + +QSGPainterNode::~QSGPainterNode() +{ + delete m_texture; + delete m_fbo; + delete m_multisampledFbo; + delete m_gl_device; +} + +void QSGPainterNode::paint() +{ + QRect dirtyRect = m_dirtyRect.isNull() ? QRect(0, 0, m_size.width(), m_size.height()) : m_dirtyRect; + + QPainter painter; + if (m_actualRenderTarget == QQuickPaintedItem::Image) + painter.begin(&m_image); + else { + if (!m_gl_device) { + m_gl_device = new QOpenGLPaintDevice(m_fboSize); + m_gl_device->setPaintFlipped(true); + } + + if (m_multisampledFbo) + m_multisampledFbo->bind(); + else + m_fbo->bind(); + + painter.begin(m_gl_device); + } + + if (m_smoothPainting) { + painter.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing + | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform); + } + + painter.scale(m_contentsScale, m_contentsScale); + + QRect sclip(qFloor(dirtyRect.x()/m_contentsScale), + qFloor(dirtyRect.y()/m_contentsScale), + qCeil(dirtyRect.width()/m_contentsScale+dirtyRect.x()/m_contentsScale-qFloor(dirtyRect.x()/m_contentsScale)), + qCeil(dirtyRect.height()/m_contentsScale+dirtyRect.y()/m_contentsScale-qFloor(dirtyRect.y()/m_contentsScale))); + + if (!m_dirtyRect.isNull()) + painter.setClipRect(sclip); + + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(sclip, m_fillColor); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + + m_item->paint(&painter); + painter.end(); + + if (m_actualRenderTarget == QQuickPaintedItem::Image) { + m_texture->setImage(m_image); + m_texture->setDirtyRect(dirtyRect); + } else if (m_multisampledFbo) { + QOpenGLFramebufferObject::blitFramebuffer(m_fbo, dirtyRect, m_multisampledFbo, dirtyRect); + } + + if (m_multisampledFbo) + m_multisampledFbo->release(); + else if (m_fbo) + m_fbo->release(); + + m_dirtyRect = QRect(); +} + +void QSGPainterNode::update() +{ + if (m_dirtyRenderTarget) + updateRenderTarget(); + if (m_dirtyGeometry) + updateGeometry(); + if (m_dirtyTexture) + updateTexture(); + + if (m_dirtyContents) + paint(); + + m_dirtyGeometry = false; + m_dirtyRenderTarget = false; + m_dirtyTexture = false; + m_dirtyContents = false; +} + +void QSGPainterNode::updateTexture() +{ + m_texture->setHasMipmaps(m_mipmapping); + m_texture->setHasAlphaChannel(!m_opaquePainting); + m_material.setTexture(m_texture); + m_materialO.setTexture(m_texture); + + markDirty(DirtyMaterial); +} + +void QSGPainterNode::updateGeometry() +{ + QRectF source; + if (m_actualRenderTarget == QQuickPaintedItem::Image) + source = QRectF(0, 0, 1, 1); + else + source = QRectF(0, 0, qreal(m_size.width()) / m_fboSize.width(), qreal(m_size.height()) / m_fboSize.height()); + QRectF dest(0, 0, m_size.width(), m_size.height()); + if (m_actualRenderTarget == QQuickPaintedItem::InvertedYFramebufferObject) + dest = QRectF(QPointF(0, m_size.height()), QPointF(m_size.width(), 0)); + QSGGeometry::updateTexturedRectGeometry(&m_geometry, + dest, + source); + markDirty(DirtyGeometry); +} + +void QSGPainterNode::updateRenderTarget() +{ + if (!m_extensionsChecked) { + QList<QByteArray> extensions = QByteArray((const char *)glGetString(GL_EXTENSIONS)).split(' '); + m_multisamplingSupported = extensions.contains("GL_EXT_framebuffer_multisample") + && extensions.contains("GL_EXT_framebuffer_blit"); + m_extensionsChecked = true; + } + + m_dirtyContents = true; + + QQuickPaintedItem::RenderTarget oldTarget = m_actualRenderTarget; + if (m_preferredRenderTarget == QQuickPaintedItem::Image) { + m_actualRenderTarget = QQuickPaintedItem::Image; + } else { + if (!m_multisamplingSupported && m_smoothPainting) + m_actualRenderTarget = QQuickPaintedItem::Image; + else + m_actualRenderTarget = m_preferredRenderTarget; + } + if (oldTarget != m_actualRenderTarget) { + m_image = QImage(); + delete m_fbo; + delete m_multisampledFbo; + m_fbo = m_multisampledFbo = 0; + } + + if (m_actualRenderTarget == QQuickPaintedItem::FramebufferObject || + m_actualRenderTarget == QQuickPaintedItem::InvertedYFramebufferObject) { + const QOpenGLContext *ctx = m_context->glContext(); + if (m_fbo && !m_dirtyGeometry && (!ctx->format().samples() || !m_multisamplingSupported)) + return; + + if (m_fboSize.isEmpty()) + updateFBOSize(); + + delete m_fbo; + delete m_multisampledFbo; + m_fbo = m_multisampledFbo = 0; + + if (m_smoothPainting && ctx->format().samples() && m_multisamplingSupported) { + { + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + format.setSamples(8); + m_multisampledFbo = new QOpenGLFramebufferObject(m_fboSize, format); + } + { + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::NoAttachment); + m_fbo = new QOpenGLFramebufferObject(m_fboSize, format); + } + } else { + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + m_fbo = new QOpenGLFramebufferObject(m_fboSize, format); + } + } else { + if (!m_image.isNull() && !m_dirtyGeometry) + return; + + m_image = QImage(m_size, QImage::Format_ARGB32_Premultiplied); + m_image.fill(Qt::transparent); + } + + QSGPainterTexture *texture = new QSGPainterTexture; + if (m_actualRenderTarget == QQuickPaintedItem::Image) { + texture->setOwnsTexture(true); + texture->setTextureSize(m_size); + } else { + texture->setTextureId(m_fbo->texture()); + texture->setOwnsTexture(false); + texture->setTextureSize(m_fboSize); + } + + if (m_texture) + delete m_texture; + + texture->setTextureSize(m_size); + m_texture = texture; +} + +void QSGPainterNode::updateFBOSize() +{ + int fboWidth; + int fboHeight; + if (m_fastFBOResizing) { + fboWidth = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qt_next_power_of_two(m_size.width())); + fboHeight = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qt_next_power_of_two(m_size.height())); + } else { + QSize minimumFBOSize = m_context->minimumFBOSize(); + fboWidth = qMax(minimumFBOSize.width(), m_size.width()); + fboHeight = qMax(minimumFBOSize.height(), m_size.height()); + } + + m_fboSize = QSize(fboWidth, fboHeight); +} + +void QSGPainterNode::setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target) +{ + if (m_preferredRenderTarget == target) + return; + + m_preferredRenderTarget = target; + + m_dirtyRenderTarget = true; + m_dirtyGeometry = true; + m_dirtyTexture = true; +} + +void QSGPainterNode::setSize(const QSize &size) +{ + if (size == m_size) + return; + + m_size = size; + updateFBOSize(); + + if (m_fbo) + m_dirtyRenderTarget = m_fbo->size() != m_fboSize || m_dirtyRenderTarget; + else + m_dirtyRenderTarget = true; + m_dirtyGeometry = true; + m_dirtyTexture = true; +} + +void QSGPainterNode::setDirty(const QRect &dirtyRect) +{ + m_dirtyContents = true; + m_dirtyRect = dirtyRect; + + if (m_mipmapping) + m_dirtyTexture = true; + + markDirty(DirtyMaterial); +} + +void QSGPainterNode::setOpaquePainting(bool opaque) +{ + if (opaque == m_opaquePainting) + return; + + m_opaquePainting = opaque; + m_dirtyTexture = true; +} + +void QSGPainterNode::setLinearFiltering(bool linearFiltering) +{ + if (linearFiltering == m_linear_filtering) + return; + + m_linear_filtering = linearFiltering; + + m_material.setFiltering(linearFiltering ? QSGTexture::Linear : QSGTexture::Nearest); + m_materialO.setFiltering(linearFiltering ? QSGTexture::Linear : QSGTexture::Nearest); + markDirty(DirtyMaterial); +} + +void QSGPainterNode::setMipmapping(bool mipmapping) +{ + if (mipmapping == m_mipmapping) + return; + + m_mipmapping = mipmapping; + m_material.setMipmapFiltering(mipmapping ? QSGTexture::Linear : QSGTexture::None); + m_materialO.setMipmapFiltering(mipmapping ? QSGTexture::Linear : QSGTexture::None); + m_dirtyTexture = true; +} + +void QSGPainterNode::setSmoothPainting(bool s) +{ + if (s == m_smoothPainting) + return; + + m_smoothPainting = s; + m_dirtyRenderTarget = true; +} + +void QSGPainterNode::setFillColor(const QColor &c) +{ + if (c == m_fillColor) + return; + + m_fillColor = c; + markDirty(DirtyMaterial); +} + +void QSGPainterNode::setContentsScale(qreal s) +{ + if (s == m_contentsScale) + return; + + m_contentsScale = s; + markDirty(DirtyMaterial); +} + +void QSGPainterNode::setFastFBOResizing(bool dynamic) +{ + m_fastFBOResizing = dynamic; +} + +QImage QSGPainterNode::toImage() const +{ + if (m_actualRenderTarget == QQuickPaintedItem::Image) + return m_image; + else + return m_fbo->toImage(); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgpainternode_p.h b/src/quick/scenegraph/util/qsgpainternode_p.h new file mode 100644 index 0000000000..85f26f6056 --- /dev/null +++ b/src/quick/scenegraph/util/qsgpainternode_p.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGPAINTERNODE_P_H +#define QSGPAINTERNODE_P_H + +#include <QtQuick/qsgnode.h> +#include "qsgtexturematerial.h" +#include "qsgtexture_p.h" + +#include <QtQuick/qquickpainteditem.h> + +#include <QtGui/qcolor.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QOpenGLFramebufferObject; +class QOpenGLPaintDevice; + +class Q_QUICK_EXPORT QSGPainterTexture : public QSGPlainTexture +{ +public: + QSGPainterTexture(); + + void setDirtyRect(const QRect &rect) { m_dirty_rect = rect; } + + void bind(); + +private: + QRect m_dirty_rect; +}; + +class Q_QUICK_EXPORT QSGPainterNode : public QSGGeometryNode +{ +public: + QSGPainterNode(QQuickPaintedItem *item); + virtual ~QSGPainterNode(); + + void setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target); + + void setSize(const QSize &size); + QSize size() const { return m_size; } + + void setDirty(const QRect &dirtyRect = QRect()); + + void setOpaquePainting(bool opaque); + bool opaquePainting() const { return m_opaquePainting; } + + void setLinearFiltering(bool linearFiltering); + bool linearFiltering() const { return m_linear_filtering; } + + void setMipmapping(bool mipmapping); + bool mipmapping() const { return m_mipmapping; } + + void setSmoothPainting(bool s); + bool smoothPainting() const { return m_smoothPainting; } + + void setFillColor(const QColor &c); + QColor fillColor() const { return m_fillColor; } + + void setContentsScale(qreal s); + qreal contentsScale() const { return m_contentsScale; } + + void setFastFBOResizing(bool dynamic); + bool fastFBOResizing() const { return m_fastFBOResizing; } + + QImage toImage() const; + void update(); + + void paint(); + +private: + void updateTexture(); + void updateGeometry(); + void updateRenderTarget(); + void updateFBOSize(); + + QSGContext *m_context; + + QQuickPaintedItem::RenderTarget m_preferredRenderTarget; + QQuickPaintedItem::RenderTarget m_actualRenderTarget; + + QQuickPaintedItem *m_item; + + QOpenGLFramebufferObject *m_fbo; + QOpenGLFramebufferObject *m_multisampledFbo; + QImage m_image; + + QSGOpaqueTextureMaterial m_material; + QSGTextureMaterial m_materialO; + QSGGeometry m_geometry; + QSGPainterTexture *m_texture; + QOpenGLPaintDevice *m_gl_device; + + QSize m_size; + QSize m_fboSize; + bool m_dirtyContents; + QRect m_dirtyRect; + bool m_opaquePainting; + bool m_linear_filtering; + bool m_mipmapping; + bool m_smoothPainting; + bool m_extensionsChecked; + bool m_multisamplingSupported; + bool m_fastFBOResizing; + QColor m_fillColor; + qreal m_contentsScale; + + bool m_dirtyGeometry; + bool m_dirtyRenderTarget; + bool m_dirtyTexture; +}; + +QT_END_HEADER + +QT_END_NAMESPACE + +#endif // QSGPAINTERNODE_P_H diff --git a/src/quick/scenegraph/util/qsgsimplematerial.h b/src/quick/scenegraph/util/qsgsimplematerial.h new file mode 100644 index 0000000000..44beb135f7 --- /dev/null +++ b/src/quick/scenegraph/util/qsgsimplematerial.h @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGSIMPLEMATERIAL_H +#define QSGSIMPLEMATERIAL_H + +#include <QtQuick/qsgmaterial.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +template <typename State> +class QSGSimpleMaterialShader : public QSGMaterialShader +{ +public: + void initialize() { + QSGMaterialShader::initialize(); + + m_id_matrix = program()->uniformLocation(uniformMatrixName()); + if (m_id_matrix < 0) { + qFatal("QSGSimpleMaterialShader does not implement 'uniform highp mat4 %s;' in its vertex shader", + uniformMatrixName()); + } + + const char *opacity = uniformOpacityName(); + if (opacity) { + m_id_opacity = program()->uniformLocation(uniformOpacityName()); + if (m_id_opacity < 0) { + qFatal("QSGSimpleMaterialShader does not implement 'uniform lowp float %s' in its fragment shader", + uniformOpacityName()); + } + } else { + m_id_opacity = -1; + } + + resolveUniforms(); + } + + const char *uniformMatrixName() const { return "qt_Matrix"; } + const char *uniformOpacityName() const { return "qt_Opacity"; } + + void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial); + + virtual void updateState(const State *newState, const State *oldState) = 0; + + virtual void resolveUniforms() {} + + virtual QList<QByteArray> attributes() const = 0; + + char const *const *attributeNames() const + { + if (m_attribute_pointers.size()) + return m_attribute_pointers.constData(); + + QList<QByteArray> names = attributes(); + + // Calculate the total number of bytes needed, so we don't get rellocs and + // bad pointers while copying over the individual names. + // Add an extra byte pr entry for the '\0' char. + int total = 0; + for (int i=0; i<names.size(); ++i) + total += names.at(i).size() + 1; + m_attribute_name_data.reserve(total); + + // Copy over the names + for (int i=0; i<names.size(); ++i) { + m_attribute_pointers << m_attribute_name_data.constData() + m_attribute_name_data.size(); + m_attribute_name_data.append(names.at(i)); + m_attribute_name_data.append('\0'); + } + + // Append the "null" terminator + m_attribute_pointers << 0; + + return m_attribute_pointers.constData(); + } + +private: + int m_id_matrix; + int m_id_opacity; + + mutable QByteArray m_attribute_name_data; + mutable QVector<const char *> m_attribute_pointers; +}; + +#define QSG_DECLARE_SIMPLE_SHADER(Shader, State) \ +static QSGMaterialShader *createShader() \ +{ \ + return new Shader; \ +} \ +public: \ +static QSGSimpleMaterial<State> *createMaterial() \ +{ \ + return new QSGSimpleMaterial<State>(createShader); \ +} + + +typedef QSGMaterialShader *(*PtrShaderCreateFunc)(); + + +template <typename State> +class QSGSimpleMaterial : public QSGMaterial +{ + +public: + QSGSimpleMaterial(const State &state, PtrShaderCreateFunc func) + : m_state(state) + , m_func(func) + { + } + + QSGSimpleMaterial(PtrShaderCreateFunc func) + : m_func(func) + { + } + + QSGMaterialShader *createShader() const { return m_func(); } + QSGMaterialType *type() const { return &m_type; } + + State *state() { return &m_state; } + const State *state() const { return &m_state; } + +private: + static QSGMaterialType m_type; + State m_state; + PtrShaderCreateFunc m_func; +}; + +#define QSG_DECLARE_SIMPLE_COMPARABLE_SHADER(Shader, State) \ +static QSGMaterialShader *createShader() \ +{ \ + return new Shader; \ +} \ +public: \ +static QSGSimpleMaterialComparableMaterial<State> *createMaterial() \ +{ \ + return new QSGSimpleMaterialComparableMaterial<State>(createShader); \ +} + +template <typename State> +class QSGSimpleMaterialComparableMaterial : public QSGSimpleMaterial<State> +{ + +public: + QSGSimpleMaterialComparableMaterial(const State &state, PtrShaderCreateFunc func) + : QSGSimpleMaterial<State>(state, func) {} + + QSGSimpleMaterialComparableMaterial(PtrShaderCreateFunc func) + : QSGSimpleMaterial<State>(func) {} + + int compare(const QSGMaterial *other) const { + return QSGSimpleMaterialComparableMaterial<State>::state()->compare(static_cast<const QSGSimpleMaterialComparableMaterial<State> *>(other)->state()); + } +}; + + +template <typename State> +QSGMaterialType QSGSimpleMaterial<State>::m_type; + + +template <typename State> +Q_INLINE_TEMPLATE void QSGSimpleMaterialShader<State>::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) +{ + if (state.isMatrixDirty()) + program()->setUniformValue(m_id_matrix, state.combinedMatrix()); + if (state.isOpacityDirty() && m_id_opacity >= 0) + program()->setUniformValue(m_id_opacity, state.opacity()); + + State *ns = static_cast<QSGSimpleMaterial<State> *>(newMaterial)->state(); + State *old = 0; + if (oldMaterial) + old = static_cast<QSGSimpleMaterial<State> *>(oldMaterial)->state(); + updateState(ns, old); +} + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/quick/scenegraph/util/qsgsimplerectnode.cpp b/src/quick/scenegraph/util/qsgsimplerectnode.cpp new file mode 100644 index 0000000000..c3dc5354ca --- /dev/null +++ b/src/quick/scenegraph/util/qsgsimplerectnode.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgsimplerectnode.h" +#include "qsgflatcolormaterial.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QSGSimpleRectNode + + \brief The QSGSimpleRectNode class is a convenience class for drawing + solid filled rectangles using scenegraph. + + */ + + + +/*! + Constructs a QSGSimpleRectNode instance which is spanning \a rect with + the color \a color. + */ +QSGSimpleRectNode::QSGSimpleRectNode(const QRectF &rect, const QColor &color) + : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4) +{ + QSGGeometry::updateRectGeometry(&m_geometry, rect); + m_material.setColor(color); + setMaterial(&m_material); + setGeometry(&m_geometry); +} + + + +/*! + Constructs a QSGSimpleRectNode instance with an empty rectangle and + white color. + */ +QSGSimpleRectNode::QSGSimpleRectNode() + : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4) +{ + QSGGeometry::updateRectGeometry(&m_geometry, QRectF()); + setMaterial(&m_material); + setGeometry(&m_geometry); +} + + + +/*! + Sets the rectangle of this rect node to \a rect. + */ +void QSGSimpleRectNode::setRect(const QRectF &rect) +{ + QSGGeometry::updateRectGeometry(&m_geometry, rect); + markDirty(QSGNode::DirtyGeometry); +} + + + +/*! + Returns the rectangle that this rect node covers. + */ +QRectF QSGSimpleRectNode::rect() const +{ + const QSGGeometry::Point2D *pts = m_geometry.vertexDataAsPoint2D(); + return QRectF(pts[0].x, + pts[0].y, + pts[3].x - pts[0].x, + pts[3].y - pts[0].y); +} + + +/*! + Sets the color of this rectangle to \a color. The default + color will be white. + */ +void QSGSimpleRectNode::setColor(const QColor &color) +{ + if (color != m_material.color()) { + m_material.setColor(color); + markDirty(QSGNode::DirtyMaterial); + } +} + + + +/*! + Returns the color of this rectangle. + */ +QColor QSGSimpleRectNode::color() const +{ + return m_material.color(); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgsimplerectnode.h b/src/quick/scenegraph/util/qsgsimplerectnode.h new file mode 100644 index 0000000000..6519290cfe --- /dev/null +++ b/src/quick/scenegraph/util/qsgsimplerectnode.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SOLIDRECTNODE_H +#define SOLIDRECTNODE_H + +#include <QtQuick/qsgnode.h> +#include "qsgflatcolormaterial.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGSimpleRectNode : public QSGGeometryNode +{ +public: + QSGSimpleRectNode(const QRectF &rect, const QColor &color); + QSGSimpleRectNode(); + + void setRect(const QRectF &rect); + inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } + QRectF rect() const; + + void setColor(const QColor &color); + QColor color() const; + +private: + QSGFlatColorMaterial m_material; + QSGGeometry m_geometry; + void *reserved; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // SOLIDRECTNODE_H diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp new file mode 100644 index 0000000000..00b240e435 --- /dev/null +++ b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qsgsimpletexturenode.h" + +QT_BEGIN_NAMESPACE + +static void qsgsimpletexturenode_update(QSGGeometry *g, + QSGTexture *texture, + const QRectF &rect) +{ + if (!texture) + return; + + QSize ts = texture->textureSize(); + QRectF sourceRect(0, 0, ts.width(), ts.height()); + QSGGeometry::updateTexturedRectGeometry(g, rect, texture->convertToNormalizedSourceRect(sourceRect)); +} + +/*! + \class QSGSimpleTextureNode + \brief The QSGSimpleTextureNode class is provided for convenience to easily draw + textured content using the QML scene graph. + + \inmodule QtQuick + + \warning The simple texture node class must have a texture before being + added to the scene graph to be rendered. +*/ + +/*! + Constructs a new simple texture node + */ +QSGSimpleTextureNode::QSGSimpleTextureNode() + : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) +{ + setGeometry(&m_geometry); + setMaterial(&m_material); + setOpaqueMaterial(&m_opaque_material); +} + +/*! + Sets the filtering to be used for this texture node to \a filtering. + + For smooth scaling, use QSGTexture::Linear; for normal scaling, use + QSGTexture::Nearest. + */ +void QSGSimpleTextureNode::setFiltering(QSGTexture::Filtering filtering) +{ + if (m_material.filtering() == filtering) + return; + + m_material.setFiltering(filtering); + m_opaque_material.setFiltering(filtering); + markDirty(DirtyMaterial); +} + + +/*! + Returns the filtering currently set on this texture node + */ +QSGTexture::Filtering QSGSimpleTextureNode::filtering() const +{ + return m_material.filtering(); +} + + +/*! + Sets the target rect of this texture node to \a r + */ +void QSGSimpleTextureNode::setRect(const QRectF &r) +{ + if (m_rect == r) + return; + m_rect = r; + qsgsimpletexturenode_update(&m_geometry, texture(), m_rect); + markDirty(DirtyGeometry); +} + + +/*! + Returns the target rect of this texture node. + */ +QRectF QSGSimpleTextureNode::rect() const +{ + return m_rect; +} + +/*! + Sets the texture of this texture node to \a texture. + + \warning A texture node must have a texture before being added + to the scenegraph to be rendered. + */ +void QSGSimpleTextureNode::setTexture(QSGTexture *texture) +{ + if (m_material.texture() == texture) + return; + m_material.setTexture(texture); + m_opaque_material.setTexture(texture); + qsgsimpletexturenode_update(&m_geometry, texture, m_rect); + markDirty(DirtyMaterial); +} + + + +/*! + Returns the texture for this texture node + */ +QSGTexture *QSGSimpleTextureNode::texture() const +{ + return m_material.texture(); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.h b/src/quick/scenegraph/util/qsgsimpletexturenode.h new file mode 100644 index 0000000000..605cae11e4 --- /dev/null +++ b/src/quick/scenegraph/util/qsgsimpletexturenode.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGSIMPLETEXTURENODE_H +#define QSGSIMPLETEXTURENODE_H + +#include <QtQuick/qsgnode.h> +#include <QtQuick/qsggeometry.h> +#include "qsgtexturematerial.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGSimpleTextureNode : public QSGGeometryNode +{ +public: + QSGSimpleTextureNode(); + + void setRect(const QRectF &rect); + inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } + QRectF rect() const; + + void setTexture(QSGTexture *texture); + QSGTexture *texture() const; + + void setFiltering(QSGTexture::Filtering filtering); + QSGTexture::Filtering filtering() const; + +private: + QSGGeometry m_geometry; + QSGOpaqueTextureMaterial m_opaque_material; + QSGTextureMaterial m_material; + + QRectF m_rect; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSGSIMPLETEXTURENODE_H diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp new file mode 100644 index 0000000000..0abbc8dae1 --- /dev/null +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -0,0 +1,541 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#define GL_GLEXT_PROTOTYPES + +#include "qsgtexture_p.h" +#include <qopenglfunctions.h> +#include <QtQuick/private/qsgcontext_p.h> +#include <qthread.h> +#include <private/qdeclarativedebugtrace_p.h> + +#if !defined(QT_NO_DEBUG) && (defined(Q_OS_LINUX) || defined(Q_OS_MAC)) +#include <execinfo.h> +#include <QHash> +#endif + +QT_BEGIN_NAMESPACE + +inline static bool isPowerOfTwo(int x) +{ + // Assumption: x >= 1 + return x == (x & -x); +} + +QSGTexturePrivate::QSGTexturePrivate() + : wrapChanged(false) + , filteringChanged(false) + , horizontalWrap(QSGTexture::ClampToEdge) + , verticalWrap(QSGTexture::ClampToEdge) + , mipmapMode(QSGTexture::None) + , filterMode(QSGTexture::Nearest) +{ +} + +#ifndef QT_NO_DEBUG + +static int qt_debug_texture_count = 0; + +#if defined(Q_OS_LINUX) || defined (Q_OS_MAC) +DEFINE_BOOL_CONFIG_OPTION(qmlDebugLeakBacktrace, QML_DEBUG_LEAK_BACKTRACE) + +#define BACKTRACE_SIZE 20 +class SGTextureTraceItem +{ +public: + void *backTrace[BACKTRACE_SIZE]; + size_t backTraceSize; +}; + +static QHash<QSGTexture*, SGTextureTraceItem*> qt_debug_allocated_textures; +#endif + +inline static void qt_debug_print_texture_count() +{ + qDebug("Number of leaked textures: %i", qt_debug_texture_count); + qt_debug_texture_count = -1; + +#if defined(Q_OS_LINUX) || defined (Q_OS_MAC) + if (qmlDebugLeakBacktrace()) { + while (!qt_debug_allocated_textures.isEmpty()) { + QHash<QSGTexture*, SGTextureTraceItem*>::Iterator it = qt_debug_allocated_textures.begin(); + QSGTexture* texture = it.key(); + SGTextureTraceItem* item = it.value(); + + qt_debug_allocated_textures.erase(it); + + qDebug() << "------"; + qDebug() << "Leaked" << texture << "backtrace:"; + + char** symbols = backtrace_symbols(item->backTrace, item->backTraceSize); + + if (symbols) { + for (int i=0; i<(int) item->backTraceSize; i++) + qDebug("Backtrace <%02d>: %s", i, symbols[i]); + free(symbols); + } + + qDebug() << "------"; + + delete item; + } + } +#endif +} + +inline static void qt_debug_add_texture(QSGTexture* texture) +{ +#if defined(Q_OS_LINUX) || defined (Q_OS_MAC) + if (qmlDebugLeakBacktrace()) { + SGTextureTraceItem* item = new SGTextureTraceItem; + item->backTraceSize = backtrace(item->backTrace, BACKTRACE_SIZE); + qt_debug_allocated_textures.insert(texture, item); + } +#else + Q_UNUSED(texture); +#endif // Q_OS_LINUX + + ++qt_debug_texture_count; + + static bool atexit_registered = false; + if (!atexit_registered) { + atexit(qt_debug_print_texture_count); + atexit_registered = true; + } +} + +static void qt_debug_remove_texture(QSGTexture* texture) +{ +#if defined(Q_OS_LINUX) || defined (Q_OS_MAC) + if (qmlDebugLeakBacktrace()) { + SGTextureTraceItem* item = qt_debug_allocated_textures.value(texture, 0); + if (item) { + qt_debug_allocated_textures.remove(texture); + delete item; + } + } +#else + Q_UNUSED(texture) +#endif + + --qt_debug_texture_count; + + if (qt_debug_texture_count < 0) + qDebug("Material destroyed after qt_debug_print_texture_count() was called."); +} + +#endif // QT_NO_DEBUG + + +QSGTexture::QSGTexture() + : QObject(*(new QSGTexturePrivate)) +{ +#ifndef QT_NO_DEBUG + qt_debug_add_texture(this); +#endif +} + +QSGTexture::~QSGTexture() +{ +#ifndef QT_NO_DEBUG + qt_debug_remove_texture(this); +#endif +} + + +/*! + \fn void QSGTexture::bind() + + Call this function to bind this texture to the current texture + target. + + Binding a texture may also include uploading the texture data from + a previously set QImage. + + \warning This function can only be called from the rendering thread. + */ + +/*! + This function returns a copy of the current texture which is removed + from its atlas. + + The current texture remains unchanged, so texture coordinates do not + need to be updated. + + Removing a texture from an atlas is primarily useful when passing + it to a shader that operates on the texture coordinates 0-1 instead + of the texture subrect inside the atlas. + + If the texture is not part of a texture atlas, this function returns 0. + + Implementations of this function are recommended to return the same instance + for multiple calls to limit memory usage. + + \warning This function can only be called from the rendering thread. + */ + +QSGTexture *QSGTexture::removedFromAtlas() const +{ + Q_ASSERT_X(!isAtlasTexture(), "QSGTexture::removedFromAtlas()", "Called on a non-atlas texture"); + return 0; +} + +/*! + Returns weither this texture is part of an atlas or not. + + The default implementation returns false. + */ +bool QSGTexture::isAtlasTexture() const +{ + return false; +} + +/*! + \fn int QSGTexture::textureId() const + + Returns the OpenGL texture id for this texture. + + The default value is 0, indicating that it is an invalid texture id. + + The function should at all times return the correct texture id. + + \warning This function can only be called from the rendering thread. + */ + + + +/*! + Returns the rectangle inside textureSize() that this texture + represents in normalized coordinates. + + The default implementation returns a rect at position (0, 0) with + width and height of 1. + */ +QRectF QSGTexture::textureSubRect() const +{ + return QRectF(0, 0, 1, 1); +} + +/*! + \fn bool QSGTexture::hasMipmaps() const + + Returns true if the texture data contains mipmap levels. + */ + + +/*! + Sets the mipmap sampling mode to be used for the upcoming bind() call to \a filter. + + Setting the mipmap filtering has no effect it the texture does not have mipmaps. + + \sa hasMipmaps() + */ +void QSGTexture::setMipmapFiltering(Filtering filter) +{ + Q_D(QSGTexture); + if (d->mipmapMode != (uint) filter) { + d->mipmapMode = filter; + d->filteringChanged = true; + } +} + +/*! + Returns whether mipmapping should be used when sampling from this texture. + */ +QSGTexture::Filtering QSGTexture::mipmapFiltering() const +{ + return (QSGTexture::Filtering) d_func()->mipmapMode; +} + + +/*! + Sets the sampling mode to be used for the upcoming bind() call to \a filter. + */ +void QSGTexture::setFiltering(QSGTexture::Filtering filter) +{ + Q_D(QSGTexture); + if (d->filterMode != (uint) filter) { + d->filterMode = filter; + d->filteringChanged = true; + } +} + +QSGTexture::Filtering QSGTexture::filtering() const +{ + return (QSGTexture::Filtering) d_func()->filterMode; +} + + + +/*! + Sets the horizontal wrap mode to be used for the upcoming bind() call to \a hwrap + */ + +void QSGTexture::setHorizontalWrapMode(WrapMode hwrap) +{ + Q_D(QSGTexture); + if ((uint) hwrap != d->horizontalWrap) { + d->horizontalWrap = hwrap; + d->wrapChanged = true; + } +} + +QSGTexture::WrapMode QSGTexture::horizontalWrapMode() const +{ + return (QSGTexture::WrapMode) d_func()->horizontalWrap; +} + + + +void QSGTexture::setVerticalWrapMode(WrapMode vwrap) +{ + Q_D(QSGTexture); + if ((uint) vwrap != d->verticalWrap) { + d->verticalWrap = vwrap; + d->wrapChanged = true; + } +} + +QSGTexture::WrapMode QSGTexture::verticalWrapMode() const +{ + return (QSGTexture::WrapMode) d_func()->verticalWrap; +} + + +/*! + Update the texture state to match the filtering, mipmap and wrap options + currently set. + + If \a force is true, all properties will be updated regardless of weither + they have changed or not. + */ +void QSGTexture::updateBindOptions(bool force) +{ + Q_D(QSGTexture); + if (force || d->filteringChanged) { + bool linear = d->filterMode == Linear; + GLint minFilter = linear ? GL_LINEAR : GL_NEAREST; + GLint magFilter = linear ? GL_LINEAR : GL_NEAREST; + + if (hasMipmaps()) { + if (d->mipmapMode == Nearest) + minFilter = linear ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST; + else if (d->mipmapMode == Linear) + minFilter = linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR; + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter); + d->filteringChanged = false; + } + + if (force || d->wrapChanged) { +#if !defined(QT_NO_DEBUG) && defined(QT_OPENGL_ES_2) + if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat) { + bool npotSupported = QOpenGLFunctions(QOpenGLContext::currentContext()).hasOpenGLFeature(QOpenGLFunctions::NPOTTextures); + QSize size = textureSize(); + bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height()); + if (!npotSupported && isNpot) + qWarning("Scene Graph: This system does not support the REPEAT wrap mode for non-power-of-two textures."); + } +#endif + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, d->horizontalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, d->verticalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); + d->wrapChanged = false; + } +} + +QSGPlainTexture::QSGPlainTexture() + : QSGTexture() + , m_texture_id(0) + , m_has_alpha(false) + , m_has_mipmaps(false) + , m_dirty_bind_options(false) + , m_owns_texture(true) + , m_mipmaps_generated(false) +{ +} + + +QSGPlainTexture::~QSGPlainTexture() +{ + if (m_texture_id && m_owns_texture) + glDeleteTextures(1, &m_texture_id); +} + +#ifdef QT_OPENGL_ES +static void swizzleBGRAToRGBA(QImage *image) +{ + const int width = image->width(); + const int height = image->height(); + for (int i = 0; i < height; ++i) { + uint *p = (uint *) image->scanLine(i); + for (int x = 0; x < width; ++x) + p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); + } +} +#endif + +void QSGPlainTexture::setImage(const QImage &image) +{ + m_image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); +#ifdef QT_OPENGL_ES + swizzleBGRAToRGBA(&m_image); +#endif + + m_texture_size = image.size(); + m_has_alpha = image.hasAlphaChannel(); + m_dirty_texture = true; + m_dirty_bind_options = true; + } + +int QSGPlainTexture::textureId() const +{ + if (m_dirty_texture) { + if (m_image.isNull()) { + // The actual texture and id will be updated/deleted in a later bind() + // or ~QSGPlainTexture so just keep it minimal here. + return 0; + } else { + // Generate a texture id for use later and return it. + glGenTextures(1, &const_cast<QSGPlainTexture *>(this)->m_texture_id); + return m_texture_id; + } + } + return m_texture_id; +} + +void QSGPlainTexture::setTextureId(int id) +{ + if (m_texture_id && m_owns_texture) + glDeleteTextures(1, &m_texture_id); + + m_texture_id = id; + m_dirty_texture = false; + m_dirty_bind_options = true; + m_image = QImage(); + m_mipmaps_generated = false; +} + +void QSGPlainTexture::setHasMipmaps(bool mm) +{ + m_has_mipmaps = mm; + m_mipmaps_generated = false; +} + + +void QSGPlainTexture::bind() +{ + if (!m_dirty_texture) { + glBindTexture(GL_TEXTURE_2D, m_texture_id); + if (m_has_mipmaps && !m_mipmaps_generated) { + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D); + m_mipmaps_generated = true; + } + updateBindOptions(m_dirty_bind_options); + m_dirty_bind_options = false; + return; + } + + m_dirty_texture = false; + + + if (m_image.isNull()) { + if (m_texture_id && m_owns_texture) + glDeleteTextures(1, &m_texture_id); + m_texture_id = 0; + m_texture_size = QSize(); + m_has_mipmaps = false; + m_has_alpha = false; + return; + } + + if (m_texture_id == 0) + glGenTextures(1, &m_texture_id); + glBindTexture(GL_TEXTURE_2D, m_texture_id); + + // ### TODO: check for out-of-memory situations... + int w = m_image.width(); + int h = m_image.height(); + +#ifdef QT_OPENGL_ES + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_image.constBits()); +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, m_image.constBits()); +#endif + + if (m_has_mipmaps) { + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D); + m_mipmaps_generated = true; + } + + m_texture_size = QSize(w, h); + m_texture_rect = QRectF(0, 0, 1, 1); + + updateBindOptions(m_dirty_bind_options); + m_dirty_bind_options = false; +} + + +/*! + \class QSGDynamicTexture + \brief The QSGDynamicTexture class serves as a baseclass for dynamically changing textures, + such as content that is rendered to FBO's. + + To update the content of the texture, call updateTexture() explicitly. Simply calling bind() + will not update the texture. + */ + + +/*! + \fn bool QSGDynamicTexture::updateTexture() + + Call this function to explicitely update the dynamic texture. Calling bind() will bind + the content that was previously updated. + + The function returns true if the texture was changed as a resul of the update; otherwise + returns false. + */ + + + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgtexture.h b/src/quick/scenegraph/util/qsgtexture.h new file mode 100644 index 0000000000..6fdab9f401 --- /dev/null +++ b/src/quick/scenegraph/util/qsgtexture.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGTEXTURE_H +#define QSGTEXTURE_H + +#include <QtQuick/qtquickglobal.h> +#include <QObject> +#include <QImage> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QSGTexturePrivate; +class Q_QUICK_EXPORT QSGTexture : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSGTexture) + +public: + QSGTexture(); + ~QSGTexture(); + + enum WrapMode { + Repeat, + ClampToEdge + }; + + enum Filtering { + None, + Nearest, + Linear + }; + + virtual int textureId() const = 0; + virtual QSize textureSize() const = 0; + virtual bool hasAlphaChannel() const = 0; + virtual bool hasMipmaps() const = 0; + + virtual QRectF textureSubRect() const; + + virtual bool isAtlasTexture() const; + + virtual QSGTexture *removedFromAtlas() const; + + virtual void bind() = 0; + void updateBindOptions(bool force = false); + + void setMipmapFiltering(Filtering filter); + QSGTexture::Filtering mipmapFiltering() const; + + void setFiltering(Filtering filter); + QSGTexture::Filtering filtering() const; + + void setHorizontalWrapMode(WrapMode hwrap); + QSGTexture::WrapMode horizontalWrapMode() const; + + void setVerticalWrapMode(WrapMode vwrap); + QSGTexture::WrapMode verticalWrapMode() const; + + inline QRectF convertToNormalizedSourceRect(const QRectF &rect) const; + +protected: + QSGTexture(QSGTexturePrivate &dd); +}; + +QRectF QSGTexture::convertToNormalizedSourceRect(const QRectF &rect) const +{ + QSize s = textureSize(); + QRectF r = textureSubRect(); + + qreal sx = r.width() / s.width(); + qreal sy = r.height() / s.height(); + + return QRectF(r.x() + rect.x() * sx, + r.y() + rect.y() * sy, + rect.width() * sx, + rect.height() * sy); +} + + +class Q_QUICK_EXPORT QSGDynamicTexture : public QSGTexture +{ + Q_OBJECT +public: + virtual bool updateTexture() = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h new file mode 100644 index 0000000000..e1d6dd0e32 --- /dev/null +++ b/src/quick/scenegraph/util/qsgtexture_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGTEXTURE_P_H +#define QSGTEXTURE_P_H + +#include <QtQuick/qtquickglobal.h> +#include <private/qobject_p.h> + +#include <QtGui/qopengl.h> + +#include "qsgtexture.h" +#include <QtQuick/private/qsgcontext_p.h> + +QT_BEGIN_NAMESPACE + +class QSGTexturePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QSGTexture); +public: + QSGTexturePrivate(); + + uint wrapChanged : 1; + uint filteringChanged : 1; + + uint horizontalWrap : 1; + uint verticalWrap : 1; + uint mipmapMode : 2; + uint filterMode : 2; +}; + +class Q_QUICK_EXPORT QSGPlainTexture : public QSGTexture +{ + Q_OBJECT +public: + QSGPlainTexture(); + virtual ~QSGPlainTexture(); + + void setOwnsTexture(bool owns) { m_owns_texture = owns; } + bool ownsTexture() const { return m_owns_texture; } + + void setTextureId(int id); + int textureId() const; + void setTextureSize(const QSize &size) { m_texture_size = size; } + QSize textureSize() const { return m_texture_size; } + + void setHasAlphaChannel(bool alpha) { m_has_alpha = alpha; } + bool hasAlphaChannel() const { return m_has_alpha; } + + void setHasMipmaps(bool mm); + bool hasMipmaps() const { return m_has_mipmaps; } + + void setImage(const QImage &image); + const QImage &image() { return m_image; } + + virtual void bind(); + + static QSGPlainTexture *fromImage(const QImage &image) { + QSGPlainTexture *t = new QSGPlainTexture(); + t->setImage(image); + return t; + } + +protected: + QImage m_image; + + GLuint m_texture_id; + QSize m_texture_size; + QRectF m_texture_rect; + + uint m_has_alpha : 1; + uint m_has_mipmaps : 1; + uint m_dirty_texture : 1; + uint m_dirty_bind_options : 1; + uint m_owns_texture : 1; + uint m_mipmaps_generated : 1; +}; + +QT_END_NAMESPACE + +#endif // QSGTEXTURE_P_H diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp new file mode 100644 index 0000000000..0bee81993c --- /dev/null +++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp @@ -0,0 +1,410 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgtexturematerial_p.h" + +#include <QtGui/qopenglshaderprogram.h> +#include <QtGui/qopenglfunctions.h> + +QT_BEGIN_NAMESPACE + +inline static bool isPowerOfTwo(int x) +{ + // Assumption: x >= 1 + return x == (x & -x); +} + +const char qt_scenegraph_texture_material_vertex_code[] = + "uniform highp mat4 qt_Matrix; \n" + "attribute highp vec4 qt_VertexPosition; \n" + "attribute highp vec2 qt_VertexTexCoord; \n" + "varying highp vec2 qt_TexCoord; \n" + "void main() { \n" + " qt_TexCoord = qt_VertexTexCoord; \n" + " gl_Position = qt_Matrix * qt_VertexPosition; \n" + "}"; + +const char qt_scenegraph_texture_material_fragment[] = + "varying highp vec2 qt_TexCoord; \n" + "uniform sampler2D qt_Texture; \n" + "void main() { \n" + " gl_FragColor = texture2D(qt_Texture, qt_TexCoord);\n" + "}"; + + +const char *QSGOpaqueTextureMaterialShader::vertexShader() const +{ + return qt_scenegraph_texture_material_vertex_code; +} + +const char *QSGOpaqueTextureMaterialShader::fragmentShader() const +{ + return qt_scenegraph_texture_material_fragment; +} + +QSGMaterialType QSGOpaqueTextureMaterialShader::type; + +char const *const *QSGOpaqueTextureMaterialShader::attributeNames() const +{ + static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 }; + return attr; +} + +void QSGOpaqueTextureMaterialShader::initialize() +{ + m_matrix_id = program()->uniformLocation("qt_Matrix"); +} + +void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) +{ + Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + QSGOpaqueTextureMaterial *tx = static_cast<QSGOpaqueTextureMaterial *>(newEffect); + QSGOpaqueTextureMaterial *oldTx = static_cast<QSGOpaqueTextureMaterial *>(oldEffect); + + QSGTexture *t = tx->texture(); + + t->setFiltering(tx->filtering()); +#ifdef QT_OPENGL_ES_2 + bool npotSupported = QOpenGLFunctions(const_cast<QOpenGLContext *>(state.context())).hasOpenGLFeature(QOpenGLFunctions::NPOTTextures); + QSize size = t->textureSize(); + bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height()); + if (!npotSupported && isNpot) { + t->setHorizontalWrapMode(QSGTexture::ClampToEdge); + t->setVerticalWrapMode(QSGTexture::ClampToEdge); + } else +#endif + { + t->setHorizontalWrapMode(tx->horizontalWrapMode()); + t->setVerticalWrapMode(tx->verticalWrapMode()); + } + t->setMipmapFiltering(tx->mipmapFiltering()); + + if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId()) + t->bind(); + else + t->updateBindOptions(); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, state.combinedMatrix()); +} + + +/*! + \class QSGOpaqueTextureMaterial + \brief The QSGOpaqueTextureMaterial class provides a convenient way of + rendering textured geometry in the scene graph. + + The opaque textured material will fill every pixel in a geometry with + the supplied texture. The material does not respect the opacity of the + QSGMaterialShader::RenderState, so opacity nodes in the parent chain + of nodes using this material, have no effect. + + The geometry to be rendered with an opaque texture material requires + vertices in attribute location 0 and texture coordinates in attribute + location 1. The texture coordinate is a 2-dimensional floating-point + tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an + attribute set compatible with this material. + + The texture to be rendered is can be set using setTexture(). How the + texure should be rendered can be specified using setMipmapFiltering(), + setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode(). + The rendering state is set on the texture instance just before it + is bound. + + The opaque textured material respects the current matrix and the alpha + channel of the texture. It will disregard the accumulated opacity in + the scenegraph. + + A texture material must have a texture set before it is used as + a material in the scene graph. + */ + + + +/*! + Creates a new QSGOpaqueTextureMaterial. + + The default mipmap filtering and filtering mode is set to + QSGTexture::Nearest. The default wrap modes is set to + QSGTexture::ClampToEdge. + + */ +QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial() + : m_texture(0) + , m_filtering(QSGTexture::Nearest) + , m_mipmap_filtering(QSGTexture::Nearest) + , m_horizontal_wrap(QSGTexture::ClampToEdge) + , m_vertical_wrap(QSGTexture::ClampToEdge) +{ +} + + +/*! + \internal + */ +QSGMaterialType *QSGOpaqueTextureMaterial::type() const +{ + return &QSGOpaqueTextureMaterialShader::type; +} + +/*! + \internal + */ +QSGMaterialShader *QSGOpaqueTextureMaterial::createShader() const +{ + return new QSGOpaqueTextureMaterialShader; +} + + + +/*! + \fn QSGTexture *QSGOpaqueTextureMaterial::texture() const + + Returns this texture material's texture. + */ + + + +/*! + Sets the texture of this material to \a texture. + + The material does not take ownership over the texture. + */ + +void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture) +{ + m_texture = texture; + setFlag(Blending, m_texture ? m_texture->hasAlphaChannel() : false); +} + + + +/*! + \fn void QSGOpaqueTextureMaterial::setMipmapFiltering(QSGTexture::Filtering filtering) + + Sets the mipmap mode to \a filtering. + + The mipmap filtering mode is set on the texture instance just before the + texture is bound for rendering. + + If the texture does not have mipmapping support, enabling mipmapping has no + effect. + */ + + + +/*! + \fn QSGTexture::Filtering QSGOpaqueTextureMaterial::mipmapFiltering() const + + Returns this material's mipmap filtering mode. + + The default mipmap mode is QSGTexture::Nearest. + */ + + + +/*! + \fn void QSGOpaqueTextureMaterial::setFiltering(QSGTexture::Filtering filtering) + + Sets the filtering to \a filtering. + + The filtering mode is set on the texture instance just before the texture + is bound for rendering. + */ + + + +/*! + \fn QSGTexture::Filtering filtering() const + + Returns this material's filtering mode. + + The default filtering is QSGTexture::Nearest. + */ + + + +/*! + \fn void setHorizontalWrapMode(QSGTexture::WrapMode mode) + + Sets the horizontal wrap mode to \a mode. + + The horizontal wrap mode is set on the texture instance just before the texture + is bound for rendering. + */ + + + + /*! + \fn QSGTexture::WrapMode horizontalWrapMode() const + + Returns this material's horizontal wrap mode. + + The default horizontal wrap mode is QSGTexutre::ClampToEdge + */ + + + +/*! + \fn void setVerticalWrapMode(QSGTexture::WrapMode mode) + + Sets the vertical wrap mode to \a mode. + + The vertical wrap mode is set on the texture instance just before the texture + is bound for rendering. + */ + + + + /*! + \fn QSGTexture::WrapMode verticalWrapMode() const + + Returns this material's vertical wrap mode. + + The default vertical wrap mode is QSGTexutre::ClampToEdge + */ + + + +/*! + \internal + */ + +int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const +{ + Q_ASSERT(o && type() == o->type()); + const QSGOpaqueTextureMaterial *other = static_cast<const QSGOpaqueTextureMaterial *>(o); + if (int diff = m_texture->textureId() - other->texture()->textureId()) + return diff; + return int(m_filtering) - int(other->m_filtering); +} + + + +/*! + \class QSGTextureMaterial + \brief The QSGTextureMaterial class provides a convenient way of + rendering textured geometry in the scene graph. + + The textured material will fill every pixel in a geometry with + the supplied texture. + + The geometry to be rendered with a texture material requires + vertices in attribute location 0 and texture coordinates in attribute + location 1. The texture coordinate is a 2-dimensional floating-point + tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an + attribute set compatible with this material. + + The texture to be rendered is set using setTexture(). How the + texure should be rendered can be specified using setMipmapFiltering(), + setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode(). + The rendering state is set on the texture instance just before it + is bound. + + The textured material respects the current matrix and the alpha + channel of the texture. It will also respect the accumulated opacity + in the scenegraph. + + A texture material must have a texture set before it is used as + a material in the scene graph. + */ + +static const char qt_scenegraph_texture_material_opacity_fragment[] = + "varying highp vec2 qt_TexCoord; \n" + "uniform sampler2D qt_Texture; \n" + "uniform lowp float opacity; \n" + "void main() { \n" + " gl_FragColor = texture2D(qt_Texture, qt_TexCoord) * opacity; \n" + "}"; + +class QSGTextureMaterialShader : public QSGOpaqueTextureMaterialShader +{ +public: + virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + virtual void initialize(); + + static QSGMaterialType type; + +protected: + virtual const char *fragmentShader() const { return qt_scenegraph_texture_material_opacity_fragment; } + + int m_opacity_id; +}; +QSGMaterialType QSGTextureMaterialShader::type; + + + +/*! + \internal + */ + +QSGMaterialType *QSGTextureMaterial::type() const +{ + return &QSGTextureMaterialShader::type; +} + + + +/*! + \internal + */ + +QSGMaterialShader *QSGTextureMaterial::createShader() const +{ + return new QSGTextureMaterialShader; +} + +void QSGTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) +{ + Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); + if (state.isOpacityDirty()) + program()->setUniformValue(m_opacity_id, state.opacity()); + + QSGOpaqueTextureMaterialShader::updateState(state, newEffect, oldEffect); +} + +void QSGTextureMaterialShader::initialize() +{ + QSGOpaqueTextureMaterialShader::initialize(); + m_opacity_id = program()->uniformLocation("opacity"); +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgtexturematerial.h b/src/quick/scenegraph/util/qsgtexturematerial.h new file mode 100644 index 0000000000..b2b3ce6374 --- /dev/null +++ b/src/quick/scenegraph/util/qsgtexturematerial.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTUREMATERIAL_H +#define TEXTUREMATERIAL_H + +#include <QtQuick/qsgmaterial.h> +#include <QtQuick/qsgtexture.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGOpaqueTextureMaterial : public QSGMaterial +{ +public: + QSGOpaqueTextureMaterial(); + + virtual QSGMaterialType *type() const; + virtual QSGMaterialShader *createShader() const; + virtual int compare(const QSGMaterial *other) const; + + void setTexture(QSGTexture *texture); + QSGTexture *texture() const { return m_texture; } + + void setMipmapFiltering(QSGTexture::Filtering filtering) { m_mipmap_filtering = filtering; } + QSGTexture::Filtering mipmapFiltering() const { return (QSGTexture::Filtering) m_mipmap_filtering; } + + void setFiltering(QSGTexture::Filtering filtering) { m_filtering = filtering; } + QSGTexture::Filtering filtering() const { return (QSGTexture::Filtering) m_filtering; } + + void setHorizontalWrapMode(QSGTexture::WrapMode mode) { m_horizontal_wrap = mode; } + QSGTexture::WrapMode horizontalWrapMode() const { return (QSGTexture::WrapMode) m_horizontal_wrap; } + + void setVerticalWrapMode(QSGTexture::WrapMode mode) { m_vertical_wrap = mode; } + QSGTexture::WrapMode verticalWrapMode() const { return (QSGTexture::WrapMode) m_vertical_wrap; } + +protected: + QSGTexture *m_texture; + + uint m_filtering: 2; + uint m_mipmap_filtering: 2; + uint m_horizontal_wrap : 1; + uint m_vertical_wrap: 1; + + uint m_reserved : 26; +}; + + +class Q_QUICK_EXPORT QSGTextureMaterial : public QSGOpaqueTextureMaterial +{ +public: + virtual QSGMaterialType *type() const; + virtual QSGMaterialShader *createShader() const; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // TEXTUREMATERIAL_H diff --git a/src/quick/scenegraph/util/qsgtexturematerial_p.h b/src/quick/scenegraph/util/qsgtexturematerial_p.h new file mode 100644 index 0000000000..0ab552f4e9 --- /dev/null +++ b/src/quick/scenegraph/util/qsgtexturematerial_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTUREMATERIAL_P_H +#define TEXTUREMATERIAL_P_H + +#include "qsgtexturematerial.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGOpaqueTextureMaterialShader : public QSGMaterialShader +{ +public: + virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + virtual char const *const *attributeNames() const; + + static QSGMaterialType type; + +protected: + virtual void initialize(); + virtual const char *vertexShader() const; + virtual const char *fragmentShader() const; + + int m_matrix_id; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QSGTEXTUREMATERIAL_P_H diff --git a/src/quick/scenegraph/util/qsgtextureprovider.cpp b/src/quick/scenegraph/util/qsgtextureprovider.cpp new file mode 100644 index 0000000000..10faf2e5d4 --- /dev/null +++ b/src/quick/scenegraph/util/qsgtextureprovider.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgtextureprovider_p.h" + +#ifndef GL_CLAMP_TO_EDGE +#define GL_CLAMP_TO_EDGE 0x812F +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QSGTextureProvider + \brief The QSGTextureProvider class encapsulates texture based entities in QML. + + The QSGTextureProvider lives primarily in the scene graph rendering thread. + */ + + + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgtextureprovider_p.h b/src/quick/scenegraph/util/qsgtextureprovider_p.h new file mode 100644 index 0000000000..bc4ffec03d --- /dev/null +++ b/src/quick/scenegraph/util/qsgtextureprovider_p.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGTEXTUREPROVIDER_H +#define QSGTEXTUREPROVIDER_H + +#include "qsgtexture.h" +#include "qobject.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGTextureProvider : public QObject +{ + Q_OBJECT +public: + virtual QSGTexture *texture() const = 0; + +Q_SIGNALS: + void textureChanged(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp new file mode 100644 index 0000000000..8c6996642b --- /dev/null +++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgvertexcolormaterial.h" + +#include <qopenglshaderprogram.h> + +QT_BEGIN_NAMESPACE + +class QSGVertexColorMaterialShader : public QSGMaterialShader +{ +public: + virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); + virtual char const *const *attributeNames() const; + + static QSGMaterialType type; + +private: + virtual void initialize(); + virtual const char *vertexShader() const; + virtual const char *fragmentShader() const; + + int m_matrix_id; + int m_opacity_id; +}; + +QSGMaterialType QSGVertexColorMaterialShader::type; + +void QSGVertexColorMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) +{ + if (!(newEffect->flags() & QSGMaterial::Blending) || state.isOpacityDirty()) + program()->setUniformValue(m_opacity_id, state.opacity()); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, state.combinedMatrix()); +} + +char const *const *QSGVertexColorMaterialShader::attributeNames() const +{ + static const char *const attr[] = { "vertexCoord", "vertexColor", 0 }; + return attr; +} + +void QSGVertexColorMaterialShader::initialize() +{ + m_matrix_id = program()->uniformLocation("matrix"); + m_opacity_id = program()->uniformLocation("opacity"); +} + +const char *QSGVertexColorMaterialShader::vertexShader() const { + return + "attribute highp vec4 vertexCoord; \n" + "attribute highp vec4 vertexColor; \n" + "uniform highp mat4 matrix; \n" + "uniform highp float opacity; \n" + "varying lowp vec4 color; \n" + "void main() { \n" + " gl_Position = matrix * vertexCoord; \n" + " color = vertexColor * opacity; \n" + "}"; +} + +const char *QSGVertexColorMaterialShader::fragmentShader() const { + return + "varying lowp vec4 color; \n" + "void main() { \n" + " gl_FragColor = color; \n" + "}"; +} + + + +/*! + \class QSGVertexColorMaterial + \brief The QSGVertexColorMaterial class provides a convenient way of rendering per-vertex + colored geometry in the scene graph. + + \inmodule QtQuick + + The vertex color material will give each vertex in a geometry a color. Pixels between + vertices will be linearly interpolated. The colors can contain transparency. + + The geometry to be rendered with vertex color must have the following layout. Attribute + position 0 must contain vertices. Attribute position 1 must contain colors, a tuple of + 4 values with RGBA layout. Both floats in the range of 0 to 1 and unsigned bytes in + the range 0 to 255 are valid for the color values. The + QSGGeometry::defaultAttributes_ColoredPoint2D() constructs an attribute set + compatible with this material. + + The vertex color material respects both current opacity and current matrix when + updating it's rendering state. + */ + + +QSGVertexColorMaterial::QSGVertexColorMaterial() +{ + setFlag(Blending, true); +} + + +/*! + int QSGVertexColorMaterial::compare() const + + As the vertex color material has all its state in the vertex attributes, + all materials will be equal. + + \internal + */ + +int QSGVertexColorMaterial::compare(const QSGMaterial * /* other */) const +{ + return 0; +} + +/*! + \internal + */ + +QSGMaterialType *QSGVertexColorMaterial::type() const +{ + return &QSGVertexColorMaterialShader::type; +} + + + +/*! + \internal + */ + +QSGMaterialShader *QSGVertexColorMaterial::createShader() const +{ + return new QSGVertexColorMaterialShader; +} + +QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.h b/src/quick/scenegraph/util/qsgvertexcolormaterial.h new file mode 100644 index 0000000000..1d3b5a82e0 --- /dev/null +++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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 Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VERTEXCOLORMATERIAL_H +#define VERTEXCOLORMATERIAL_H + +#include <QtQuick/qsgmaterial.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class Q_QUICK_EXPORT QSGVertexColorMaterial : public QSGMaterial +{ +public: + QSGVertexColorMaterial(); + + int compare(const QSGMaterial *other) const; + +protected: + virtual QSGMaterialType *type() const; + virtual QSGMaterialShader *createShader() const; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // VERTEXCOLORMATERIAL_H |