aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/scenegraph
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/scenegraph')
-rw-r--r--src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp528
-rw-r--r--src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h96
-rw-r--r--src/declarative/scenegraph/coreapi/qsggeometry.cpp310
-rw-r--r--src/declarative/scenegraph/coreapi/qsggeometry.h254
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmaterial.cpp199
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmaterial.h141
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp380
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h104
-rw-r--r--src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h73
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnode.cpp837
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnode.h363
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp243
-rw-r--r--src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h87
-rw-r--r--src/declarative/scenegraph/coreapi/qsgrenderer.cpp544
-rw-r--r--src/declarative/scenegraph/coreapi/qsgrenderer_p.h219
-rw-r--r--src/declarative/scenegraph/qsgadaptationlayer.cpp42
-rw-r--r--src/declarative/scenegraph/qsgadaptationlayer_p.h123
-rw-r--r--src/declarative/scenegraph/qsgcontext.cpp428
-rw-r--r--src/declarative/scenegraph/qsgcontext_p.h124
-rw-r--r--src/declarative/scenegraph/qsgcontextplugin.cpp104
-rw-r--r--src/declarative/scenegraph/qsgcontextplugin_p.h81
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode.cpp95
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp313
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode_p.h83
-rw-r--r--src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h95
-rw-r--r--src/declarative/scenegraph/qsgdefaultimagenode.cpp180
-rw-r--r--src/declarative/scenegraph/qsgdefaultimagenode_p.h90
-rw-r--r--src/declarative/scenegraph/qsgdefaultrectanglenode.cpp550
-rw-r--r--src/declarative/scenegraph/qsgdefaultrectanglenode_p.h106
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp939
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h158
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp223
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp656
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h93
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h128
-rw-r--r--src/declarative/scenegraph/qsgflashnode.cpp62
-rw-r--r--src/declarative/scenegraph/qsgflashnode_p.h69
-rw-r--r--src/declarative/scenegraph/scenegraph.pri80
-rw-r--r--src/declarative/scenegraph/util/qsgareaallocator.cpp290
-rw-r--r--src/declarative/scenegraph/util/qsgareaallocator_p.h73
-rw-r--r--src/declarative/scenegraph/util/qsgengine.cpp244
-rw-r--r--src/declarative/scenegraph/util/qsgengine.h100
-rw-r--r--src/declarative/scenegraph/util/qsgflatcolormaterial.cpp140
-rw-r--r--src/declarative/scenegraph/util/qsgflatcolormaterial.h71
-rw-r--r--src/declarative/scenegraph/util/qsgpainternode.cpp373
-rw-r--r--src/declarative/scenegraph/util/qsgpainternode_p.h140
-rw-r--r--src/declarative/scenegraph/util/qsgsimplerectnode.cpp132
-rw-r--r--src/declarative/scenegraph/util/qsgsimplerectnode.h77
-rw-r--r--src/declarative/scenegraph/util/qsgsimpletexturenode.cpp152
-rw-r--r--src/declarative/scenegraph/util/qsgsimpletexturenode.h82
-rw-r--r--src/declarative/scenegraph/util/qsgtexture.cpp400
-rw-r--r--src/declarative/scenegraph/util/qsgtexture.h132
-rw-r--r--src/declarative/scenegraph/util/qsgtexture_p.h112
-rw-r--r--src/declarative/scenegraph/util/qsgtexturematerial.cpp200
-rw-r--r--src/declarative/scenegraph/util/qsgtexturematerial.h100
-rw-r--r--src/declarative/scenegraph/util/qsgtexturematerial_p.h73
-rw-r--r--src/declarative/scenegraph/util/qsgtextureprovider.cpp65
-rw-r--r--src/declarative/scenegraph/util/qsgtextureprovider_p.h70
-rw-r--r--src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp136
-rw-r--r--src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h73
60 files changed, 12435 insertions, 0 deletions
diff --git a/src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp
new file mode 100644
index 0000000000..4569e7fc32
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer.cpp
@@ -0,0 +1,528 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#define GL_GLEXT_PROTOTYPES
+
+#include "qsgdefaultrenderer_p.h"
+#include "qsgmaterial.h"
+
+#include <QtCore/qvarlengtharray.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/qpair.h>
+#include <QtCore/QElapsedTimer>
+
+//#define FORCE_NO_REORDER
+
+// #define RENDERER_DEBUG
+#ifdef RENDERER_DEBUG
+#define DEBUG_THRESHOLD 0
+QElapsedTimer debugTimer;
+int materialChanges;
+int geometryNodesDrawn;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static bool nodeLessThan(QSGGeometryNode *a, QSGGeometryNode *b)
+{
+ // Sort by clip...
+ if (a->clipList() != b->clipList())
+ return a->clipList() < b->clipList();
+
+ // Sort by material definition
+ QSGMaterialType *aDef = a->material()->type();
+ QSGMaterialType *bDef = b->material()->type();
+
+ if (aDef != bDef)
+ return aDef < bDef;
+
+ // Sort by material state
+ int cmp = a->material()->compare(b->material());
+ if (cmp != 0)
+ return cmp < 0;
+
+ return a->matrix() < b->matrix();
+}
+
+static bool nodeLessThanWithRenderOrder(QSGGeometryNode *a, QSGGeometryNode *b)
+{
+ // Sort by clip...
+ if (a->clipList() != b->clipList())
+ return a->clipList() < b->clipList();
+
+ // Sort by material definition
+ QSGMaterialType *aDef = a->material()->type();
+ QSGMaterialType *bDef = b->material()->type();
+
+ if (!(a->material()->flags() & QSGMaterial::Blending)) {
+ int aOrder = a->renderOrder();
+ int bOrder = b->renderOrder();
+ if (aOrder != bOrder)
+ return aOrder > bOrder;
+ }
+
+ if (aDef != bDef)
+ return aDef < bDef;
+
+ // Sort by material state
+ int cmp = a->material()->compare(b->material());
+ if (cmp != 0)
+ return cmp < 0;
+
+ return a->matrix() < b->matrix();
+}
+
+// Minimum heap.
+template <typename T, int prealloc = 256>
+class Heap
+{
+public:
+ void insert(const T &x);
+ const T &top() const { return v[0]; }
+ T pop();
+ bool isEmpty() const { return v.isEmpty(); }
+private:
+ static int parent(int i) { return (i - 1) >> 1; }
+ static int left(int i) { return (i << 1) | 1; }
+ static int right(int i) { return (i + 1) << 1; }
+ QVarLengthArray<T, prealloc> v;
+};
+
+template <typename T, int prealloc>
+void Heap<T, prealloc>::insert(const T &x)
+{
+ int i = v.size();
+ v.append(x);
+ while (i != 0 && v[i] < v[parent(i)]) {
+ qSwap(v[parent(i)], v[i]);
+ i = parent(i);
+ }
+}
+
+template <typename T, int prealloc>
+T Heap<T, prealloc>::pop()
+{
+ T x = top();
+ if (v.size() > 1)
+ qSwap(v[0], v[v.size() - 1]);
+ v.resize(v.size() - 1);
+ int i = 0;
+ while (left(i) < v.size()) {
+ int low = left(i);
+ if (right(i) < v.size() && v[right(i)] < v[low])
+ low = right(i);
+ if (!(v[low] < v[i]))
+ break;
+ qSwap(v[i], v[low]);
+ i = low;
+ }
+ return x;
+}
+
+
+QMLRenderer::QMLRenderer(QSGContext *context)
+ : QSGRenderer(context)
+ , m_rebuild_lists(false)
+ , m_needs_sorting(false)
+ , m_sort_front_to_back(false)
+ , m_currentRenderOrder(1)
+{
+ QStringList args = qApp->arguments();
+#if defined(QML_RUNTIME_TESTING)
+ m_render_opaque_nodes = !args.contains(QLatin1String("--no-opaque-nodes"));
+ m_render_alpha_nodes = !args.contains(QLatin1String("--no-alpha-nodes"));
+#endif
+}
+
+void QMLRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags)
+{
+ QSGRenderer::nodeChanged(node, flags);
+
+ quint32 rebuildFlags = QSGNode::DirtyNodeAdded | QSGNode::DirtyNodeRemoved | QSGNode::DirtyMaterial | QSGNode::DirtyOpacity;
+
+ if (flags & rebuildFlags)
+ m_rebuild_lists = true;
+
+ if (flags & (rebuildFlags | QSGNode::DirtyClipList))
+ m_needs_sorting = true;
+}
+
+void QMLRenderer::render()
+{
+#if defined (QML_RUNTIME_TESTING)
+ static bool dumpTree = qApp->arguments().contains(QLatin1String("--dump-tree"));
+ if (dumpTree) {
+ printf("\n\n");
+ QSGNodeDumper::dump(rootNode());
+ }
+#endif
+
+#ifdef RENDERER_DEBUG
+ debugTimer.invalidate();
+ debugTimer.start();
+ geometryNodesDrawn = 0;
+ materialChanges = 0;
+#endif
+
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_BLEND);
+
+ glFrontFace(isMirrored() ? GL_CW : GL_CCW);
+ glDisable(GL_CULL_FACE);
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(true);
+ glDepthFunc(GL_GREATER);
+#if defined(QT_OPENGL_ES)
+ glClearDepthf(0);
+#else
+ glClearDepth(0);
+#endif
+
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(m_clear_color.redF(), m_clear_color.greenF(), m_clear_color.blueF(), m_clear_color.alphaF());
+
+#ifdef RENDERER_DEBUG
+ int debugtimeSetup = debugTimer.elapsed();
+#endif
+
+ bindable()->clear(clearMode());
+
+#ifdef RENDERER_DEBUG
+ int debugtimeClear = debugTimer.elapsed();
+#endif
+
+ QRect r = viewportRect();
+ glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
+ m_projectionMatrix = projectMatrix();
+ m_projectionMatrix.push();
+ m_modelViewMatrix.setToIdentity();
+
+ m_currentClip = 0;
+ glDisable(GL_STENCIL_TEST);
+
+ m_currentMaterial = 0;
+ m_currentProgram = 0;
+ m_currentMatrix = 0;
+
+ if (m_rebuild_lists) {
+ m_opaqueNodes.clear();
+ m_transparentNodes.clear();
+ m_currentRenderOrder = 1;
+ buildLists(rootNode());
+ m_rebuild_lists = false;
+ }
+
+#ifdef RENDERER_DEBUG
+ int debugtimeLists = debugTimer.elapsed();
+#endif
+
+
+ if (m_needs_sorting) {
+ qSort(m_opaqueNodes.begin(), m_opaqueNodes.end(),
+ m_sort_front_to_back
+ ? nodeLessThanWithRenderOrder
+ : nodeLessThan);
+ m_needs_sorting = false;
+ }
+
+#ifdef RENDERER_DEBUG
+ int debugtimeSorting = debugTimer.elapsed();
+#endif
+
+ m_renderOrderMatrix.setToIdentity();
+ m_renderOrderMatrix.scale(1, 1, qreal(1) / m_currentRenderOrder);
+
+ glDisable(GL_BLEND);
+ glDepthMask(true);
+#ifdef QML_RUNTIME_TESTING
+ if (m_render_opaque_nodes)
+#endif
+ {
+#if defined (QML_RUNTIME_TESTING)
+ if (dumpTree)
+ qDebug() << "Opaque Nodes:";
+#endif
+ renderNodes(m_opaqueNodes);
+ }
+
+#ifdef RENDERER_DEBUG
+ int debugtimeOpaque = debugTimer.elapsed();
+ int opaqueNodes = geometryNodesDrawn;
+ int opaqueMaterialChanges = materialChanges;
+#endif
+
+ glEnable(GL_BLEND);
+ glDepthMask(false);
+#ifdef QML_RUNTIME_TESTING
+ if (m_render_alpha_nodes)
+#endif
+ {
+#if defined (QML_RUNTIME_TESTING)
+ if (dumpTree)
+ qDebug() << "Alpha Nodes:";
+#endif
+ renderNodes(m_transparentNodes);
+ }
+
+#ifdef RENDERER_DEBUG
+ int debugtimeAlpha = debugTimer.elapsed();
+#endif
+
+
+ if (m_currentProgram)
+ m_currentProgram->deactivate();
+
+ m_projectionMatrix.pop();
+
+#ifdef RENDERER_DEBUG
+ if (debugTimer.elapsed() > DEBUG_THRESHOLD) {
+ printf(" --- Renderer breakdown:\n"
+ " - setup=%d, clear=%d, building=%d, sorting=%d, opaque=%d, alpha=%d\n"
+ " - material changes: opaque=%d, alpha=%d, total=%d\n"
+ " - geometry ndoes: opaque=%d, alpha=%d, total=%d\n",
+ debugtimeSetup,
+ debugtimeClear - debugtimeSetup,
+ debugtimeLists - debugtimeClear,
+ debugtimeSorting - debugtimeLists,
+ debugtimeOpaque - debugtimeSorting,
+ debugtimeAlpha - debugtimeOpaque,
+ opaqueMaterialChanges, materialChanges - opaqueMaterialChanges, materialChanges,
+ opaqueNodes, geometryNodesDrawn - opaqueNodes, geometryNodesDrawn);
+ }
+#endif
+
+}
+
+class Foo : public QPair<int, QSGGeometryNode *>
+{
+public:
+ Foo() { }
+ Foo(int i, QSGGeometryNode *n) : QPair<int, QSGGeometryNode *>(i, n) { }
+ bool operator < (const Foo &other) const { return nodeLessThan(second, other.second); }
+};
+
+void QMLRenderer::setSortFrontToBackEnabled(bool sort)
+{
+ printf("setting sorting to... %d\n", sort);
+ m_sort_front_to_back = sort;
+}
+
+bool QMLRenderer::isSortFrontToBackEnabled() const
+{
+ return m_sort_front_to_back;
+}
+
+void QMLRenderer::buildLists(QSGNode *node)
+{
+ if (node->isSubtreeBlocked())
+ return;
+
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *geomNode = static_cast<QSGGeometryNode *>(node);
+ qreal opacity = geomNode->inheritedOpacity();
+ QSGMaterial *m = geomNode->activeMaterial();
+
+#ifdef FORCE_NO_REORDER
+ if (true) {
+#else
+ if ((m->flags() & QSGMaterial::Blending) || opacity < 1) {
+#endif
+ geomNode->setRenderOrder(m_currentRenderOrder - 1);
+ m_transparentNodes.append(geomNode);
+ } else {
+ geomNode->setRenderOrder(m_currentRenderOrder);
+ m_opaqueNodes.append(geomNode);
+ m_currentRenderOrder += 2;
+ }
+ }
+
+ int count = node->childCount();
+ if (!count)
+ return;
+
+#ifdef FORCE_NO_REORDER
+ static bool reorder = false;
+#else
+ static bool reorder = !qApp->arguments().contains(QLatin1String("--no-reorder"));
+#endif
+
+ if (reorder && count > 1 && (node->flags() & QSGNode::ChildrenDoNotOverlap)) {
+ QVarLengthArray<int, 16> beginIndices(count);
+ QVarLengthArray<int, 16> endIndices(count);
+ int baseCount = m_transparentNodes.size();
+ for (int i = 0; i < count; ++i) {
+ beginIndices[i] = m_transparentNodes.size();
+ buildLists(node->childAtIndex(i));
+ endIndices[i] = m_transparentNodes.size();
+ }
+
+ Heap<Foo, 16> heap;
+ m_tempNodes.clear();
+ int childNodeCount = m_transparentNodes.size() - baseCount;
+ while (childNodeCount) {
+ for (int i = 0; i < count; ++i) {
+ if (beginIndices[i] != endIndices[i])
+ heap.insert(Foo(i, m_transparentNodes.at(beginIndices[i]++)));
+ }
+ while (!heap.isEmpty()) {
+ Foo foo = heap.pop();
+ m_tempNodes.append(foo.second);
+ --childNodeCount;
+ int i = foo.first;
+ if (beginIndices[i] != endIndices[i] && !nodeLessThan(m_transparentNodes.at(beginIndices[i]), foo.second))
+ heap.insert(Foo(i, m_transparentNodes.at(beginIndices[i]++)));
+ }
+ }
+ Q_ASSERT(m_tempNodes.size() == m_transparentNodes.size() - baseCount);
+
+ m_transparentNodes.resize(baseCount);
+ m_transparentNodes << m_tempNodes;
+ } else {
+ for (int i = 0; i < count; ++i)
+ buildLists(node->childAtIndex(i));
+ }
+}
+
+void QMLRenderer::renderNodes(const QVector<QSGGeometryNode *> &list)
+{
+ const float scale = 1.0f / m_currentRenderOrder;
+ int count = list.count();
+ int currentRenderOrder = 0x80000000;
+
+ //int clipChangeCount = 0;
+ //int programChangeCount = 0;
+ //int materialChangeCount = 0;
+
+ for (int i = 0; i < count; ++i) {
+ QSGGeometryNode *geomNode = list.at(i);
+
+ QSGMaterialShader::RenderState::DirtyStates updates;
+
+#if defined (QML_RUNTIME_TESTING)
+ static bool dumpTree = qApp->arguments().contains(QLatin1String("--dump-tree"));
+ if (dumpTree)
+ qDebug() << geomNode;
+#endif
+
+ bool changeMatrix = m_currentMatrix != geomNode->matrix();
+
+ if (changeMatrix) {
+ m_currentMatrix = geomNode->matrix();
+ if (m_currentMatrix)
+ m_modelViewMatrix = *m_currentMatrix;
+ else
+ m_modelViewMatrix.setToIdentity();
+ updates |= QSGMaterialShader::RenderState::DirtyMatrix;
+ }
+
+ bool changeOpacity = m_render_opacity != geomNode->inheritedOpacity();
+ if (changeOpacity) {
+ updates |= QSGMaterialShader::RenderState::DirtyOpacity;
+ m_render_opacity = geomNode->inheritedOpacity();
+ }
+
+
+ Q_ASSERT(geomNode->activeMaterial());
+
+ QSGMaterial *material = geomNode->activeMaterial();
+ QSGMaterialShader *program = m_context->prepareMaterial(material);
+
+ bool changeClip = geomNode->clipList() != m_currentClip;
+ QSGRenderer::ClipType clipType = QSGRenderer::NoClip;
+ if (changeClip) {
+ clipType = updateStencilClip(geomNode->clipList());
+ m_currentClip = geomNode->clipList();
+#ifdef FORCE_NO_REORDER
+ glDepthMask(false);
+#else
+ glDepthMask((material->flags() & QSGMaterial::Blending) == 0 && m_render_opacity == 1);
+#endif
+ //++clipChangeCount;
+ }
+
+ bool changeProgram = (changeClip && clipType == QSGRenderer::StencilClip) || m_currentProgram != program;
+ if (changeProgram) {
+ if (m_currentProgram)
+ m_currentProgram->deactivate();
+ m_currentProgram = program;
+ m_currentProgram->activate();
+ //++programChangeCount;
+ updates |= (QSGMaterialShader::RenderState::DirtyMatrix | QSGMaterialShader::RenderState::DirtyOpacity);
+
+#ifdef RENDERER_DEBUG
+ materialChanges++;
+#endif
+ }
+
+ bool changeRenderOrder = currentRenderOrder != geomNode->renderOrder();
+ if (changeRenderOrder) {
+ currentRenderOrder = geomNode->renderOrder();
+ m_renderOrderMatrix(2, 3) = currentRenderOrder * scale;
+ m_projectionMatrix.pop();
+ m_projectionMatrix.push();
+ m_projectionMatrix *= m_renderOrderMatrix;
+ updates |= QSGMaterialShader::RenderState::DirtyMatrix;
+ }
+
+ if (changeProgram || m_currentMaterial != material) {
+ program->updateState(state(updates), material, changeProgram ? 0 : m_currentMaterial);
+ m_currentMaterial = material;
+ //++materialChangeCount;
+ }
+
+ //glDepthRange((geomNode->renderOrder() + 0.1) * scale, (geomNode->renderOrder() + 0.9) * scale);
+
+ const QSGGeometry *g = geomNode->geometry();
+ bindGeometry(program, g);
+ draw(geomNode);
+
+#ifdef RENDERER_DEBUG
+ geometryNodesDrawn++;
+#endif
+ }
+ //qDebug("Clip: %i, shader program: %i, material: %i times changed while drawing %s items",
+ // clipChangeCount, programChangeCount, materialChangeCount,
+ // &list == &m_transparentNodes ? "transparent" : "opaque");
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h
new file mode 100644
index 0000000000..805388a06f
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgdefaultrenderer_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLRENDERER_H
+#define QMLRENDERER_H
+
+#include "qsgrenderer_p.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QMLRenderer : public QSGRenderer
+{
+ Q_OBJECT
+public:
+ QMLRenderer(QSGContext *context);
+
+ void render();
+
+ void nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags);
+
+ void setSortFrontToBackEnabled(bool sort);
+ bool isSortFrontToBackEnabled() const;
+
+private:
+ void buildLists(QSGNode *node);
+ void renderNodes(const QVector <QSGGeometryNode *> &list);
+
+ const QSGClipNode *m_currentClip;
+ QSGMaterial *m_currentMaterial;
+ QSGMaterialShader *m_currentProgram;
+ const QMatrix4x4 *m_currentMatrix;
+ QMatrix4x4 m_renderOrderMatrix;
+ QVector<QSGGeometryNode *> m_opaqueNodes;
+ QVector<QSGGeometryNode *> m_transparentNodes;
+ QVector<QSGGeometryNode *> m_tempNodes;
+
+ bool m_rebuild_lists;
+ bool m_needs_sorting;
+ bool m_sort_front_to_back;
+ int m_currentRenderOrder;
+
+
+
+#ifdef QML_RUNTIME_TESTING
+ bool m_render_opaque_nodes;
+ bool m_render_alpha_nodes;
+#endif
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMLRENDERER_H
diff --git a/src/declarative/scenegraph/coreapi/qsggeometry.cpp b/src/declarative/scenegraph/coreapi/qsggeometry.cpp
new file mode 100644
index 0000000000..1bfffae0bf
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsggeometry.cpp
@@ -0,0 +1,310 @@
+/****************************************************************************
+**
+** 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 Qt scene graph research project.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsggeometry.h"
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ Convenience function which returns attributes to be used for 2D solid
+ color drawing.
+ */
+
+const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_Point2D()
+{
+ static Attribute data[] = {
+ { 0, 2, GL_FLOAT }
+ };
+ static AttributeSet attrs = { 1, sizeof(float) * 2, data };
+ return attrs;
+}
+
+/*!
+ Convenience function which returns attributes to be used for textured 2D drawing.
+ */
+
+const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_TexturedPoint2D()
+{
+ static Attribute data[] = {
+ { 0, 2, GL_FLOAT },
+ { 1, 2, GL_FLOAT }
+ };
+ static AttributeSet attrs = { 2, sizeof(float) * 4, data };
+ return attrs;
+}
+
+/*!
+ Convenience function which returns attributes to be used for per vertex colored 2D drawing.
+ */
+
+const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D()
+{
+ static Attribute data[] = {
+ { 0, 2, GL_FLOAT },
+ { 1, 4, GL_UNSIGNED_BYTE }
+ };
+ static AttributeSet attrs = { 2, 2 * sizeof(float) + 4 * sizeof(char), data };
+ return attrs;
+}
+
+
+/*!
+ \class QSGGeometry
+ \brief The QSGGeometry class provides low-level storage for graphics primitives
+ in the QML Scene Graph.
+
+ The QSGGeometry class provides a few convenience attributes and attribute accessors
+ by default. The defaultAttributes_Point2D() function returns attributes to be used
+ in normal solid color rectangles, while the defaultAttributes_TexturedPoint2D function
+ returns attributes to be used for the common pixmap usecase.
+ */
+
+
+/*!
+ Constructs a geometry object based on \a attributes.
+
+ The object allocate space for \a vertexCount vertices based on the accumulated
+ size in \a attributes and for \a indexCount.
+
+ Geometry objects are constructed with GL_TRIANGLE_STRIP as default drawing mode.
+
+ The attribute structure is assumed to be POD and the geometry object
+ assumes this will not go away. There is no memory management involved.
+ */
+
+QSGGeometry::QSGGeometry(const QSGGeometry::AttributeSet &attributes,
+ int vertexCount,
+ int indexCount,
+ int indexType)
+ : m_drawing_mode(GL_TRIANGLE_STRIP)
+ , m_vertex_count(0)
+ , m_index_count(0)
+ , m_index_type(indexType)
+ , m_attributes(attributes)
+ , m_data(0)
+ , m_index_data_offset(-1)
+ , m_owns_data(false)
+{
+ Q_ASSERT(m_attributes.count > 0);
+ Q_ASSERT(m_attributes.stride > 0);
+
+ // Because allocate reads m_vertex_count, m_index_count and m_owns_data, these
+ // need to be set before calling allocate...
+ allocate(vertexCount, indexCount);
+}
+
+QSGGeometry::~QSGGeometry()
+{
+ if (m_owns_data)
+ qFree(m_data);
+}
+
+/*!
+ \fn int QSGGeometry::vertexCount() const
+
+ Returns the number of vertices in this geometry object.
+ */
+
+/*!
+ \fn int QSGGeometry::indexCount() const
+
+ Returns the number of indices in this geometry object.
+ */
+
+
+
+/*!
+ \fn void *QSGGeometry::vertexData()
+
+ Returns a pointer to the raw vertex data of this geometry object.
+
+ \sa vertexDataAsPoint2D(), vertexDataAsTexturedPoint2D
+ */
+
+/*!
+ \fn const void *QSGGeometry::vertexData() const
+
+ Returns a pointer to the raw vertex data of this geometry object.
+
+ \sa vertexDataAsPoint2D(), vertexDataAsTexturedPoint2D
+ */
+
+/*!
+ Returns a pointer to the raw index data of this geometry object.
+
+ \sa indexDataAsUShort(), indexDataAsUInt()
+ */
+void *QSGGeometry::indexData()
+{
+ return m_index_data_offset < 0
+ ? 0
+ : ((char *) m_data + m_index_data_offset);
+}
+
+/*!
+ Returns a pointer to the raw index data of this geometry object.
+
+ \sa indexDataAsUShort(), indexDataAsUInt()
+ */
+const void *QSGGeometry::indexData() const
+{
+ return m_index_data_offset < 0
+ ? 0
+ : ((char *) m_data + m_index_data_offset);
+}
+
+/*!
+ Sets the drawing mode to be used for this geometry.
+
+ The default value is GL_TRIANGLE_STRIP.
+ */
+void QSGGeometry::setDrawingMode(GLenum mode)
+{
+ m_drawing_mode = mode;
+}
+
+/*!
+ \fn int QSGGeometry::drawingMode() const
+
+ Returns the drawing mode of this geometry.
+
+ The default value is GL_TRIANGLE_STRIP.
+ */
+
+/*!
+ \fn int QSGGeometry::indexType() const
+
+ Returns the primitive type used for indices in this
+ geometry object.
+ */
+
+
+/*!
+ Resizes the vertex and index data of this geometry object to fit \a vertexCount
+ vertices and \a indexCount indices.
+
+ Vertex and index data will be invalidated after this call and the caller must
+ */
+void QSGGeometry::allocate(int vertexCount, int indexCount)
+{
+ if (vertexCount == m_vertex_count && indexCount == m_index_count)
+ return;
+
+ m_vertex_count = vertexCount;
+ m_index_count = indexCount;
+
+ bool canUsePrealloc = m_index_count <= 0;
+ int vertexByteSize = m_attributes.stride * m_vertex_count;
+
+ if (m_owns_data)
+ qFree(m_data);
+
+ if (canUsePrealloc && vertexByteSize <= (int) sizeof(m_prealloc)) {
+ m_data = (void *) &m_prealloc[0];
+ m_index_data_offset = -1;
+ m_owns_data = false;
+ } else {
+ Q_ASSERT(m_index_type == GL_UNSIGNED_INT || m_index_type == GL_UNSIGNED_SHORT);
+ int indexByteSize = indexCount * (m_index_type == GL_UNSIGNED_SHORT ? sizeof(quint16) : sizeof(quint32));
+ m_data = (void *) qMalloc(vertexByteSize + indexByteSize);
+ m_index_data_offset = vertexByteSize;
+ m_owns_data = true;
+ }
+
+}
+
+/*!
+ Updates the geometry \a g with the coordinates in \a rect.
+
+ The function assumes the geometry object contains a single triangle strip
+ of QSGGeometry::Point2D vertices
+ */
+void QSGGeometry::updateRectGeometry(QSGGeometry *g, const QRectF &rect)
+{
+ Point2D *v = g->vertexDataAsPoint2D();
+ v[0].x = rect.left();
+ v[0].y = rect.top();
+
+ v[1].x = rect.left();
+ v[1].y = rect.bottom();
+
+ v[2].x = rect.right();
+ v[2].y = rect.top();
+
+ v[3].x = rect.right();
+ v[3].y = rect.bottom();
+}
+
+/*!
+ Updates the geometry \a g with the coordinates in \a rect and texture
+ coordinates from \a textureRect.
+
+ \a textureRect should be in normalized coordinates.
+
+ \a g is assumed to be a triangle strip of four vertices of type
+ QSGGeometry::TexturedPoint2D.
+ */
+void QSGGeometry::updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect, const QRectF &textureRect)
+{
+ TexturedPoint2D *v = g->vertexDataAsTexturedPoint2D();
+ v[0].x = rect.left();
+ v[0].y = rect.top();
+ v[0].tx = textureRect.left();
+ v[0].ty = textureRect.top();
+
+ v[1].x = rect.left();
+ v[1].y = rect.bottom();
+ v[1].tx = textureRect.left();
+ v[1].ty = textureRect.bottom();
+
+ v[2].x = rect.right();
+ v[2].y = rect.top();
+ v[2].tx = textureRect.right();
+ v[2].ty = textureRect.top();
+
+ v[3].x = rect.right();
+ v[3].y = rect.bottom();
+ v[3].tx = textureRect.right();
+ v[3].ty = textureRect.bottom();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsggeometry.h b/src/declarative/scenegraph/coreapi/qsggeometry.h
new file mode 100644
index 0000000000..514fdc466f
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsggeometry.h
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** 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 Qt scene graph research project.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGGEOMETRY_H
+#define QSGGEOMETRY_H
+
+#include <QtOpenGL/qgl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QSGGeometry
+{
+public:
+ struct Attribute
+ {
+ int position;
+ int tupleSize;
+ int type;
+ };
+
+ struct AttributeSet {
+ int count;
+ int stride;
+ const Attribute *attributes;
+ };
+
+ struct Point2D {
+ float x, y;
+ void set(float nx, float ny) {
+ x = nx; y = ny;
+ }
+ };
+ struct TexturedPoint2D {
+ float x, y;
+ float tx, ty;
+ void set(float nx, float ny, float ntx, float nty) {
+ x = nx; y = ny; tx = ntx; ty = nty;
+ }
+ };
+ struct ColoredPoint2D {
+ float x, y;
+ unsigned char r, g, b, a;
+ void set(float nx, float ny, uchar nr, uchar ng, uchar nb, uchar na) {
+ x = nx; y = ny;
+ r = nr; g = ng, b = nb; a = na;
+ }
+ };
+
+ static const AttributeSet &defaultAttributes_Point2D();
+ static const AttributeSet &defaultAttributes_TexturedPoint2D();
+ static const AttributeSet &defaultAttributes_ColoredPoint2D();
+
+ QSGGeometry(const QSGGeometry::AttributeSet &attribs,
+ int vertexCount,
+ int indexCount = 0,
+ int indexType = GL_UNSIGNED_SHORT);
+ virtual ~QSGGeometry();
+
+ void setDrawingMode(GLenum mode);
+ inline GLenum drawingMode() const { return m_drawing_mode; }
+
+ void allocate(int vertexCount, int indexCount = 0);
+
+ int vertexCount() const { return m_vertex_count; }
+
+ void *vertexData() { return m_data; }
+ inline Point2D *vertexDataAsPoint2D();
+ inline TexturedPoint2D *vertexDataAsTexturedPoint2D();
+ inline ColoredPoint2D *vertexDataAsColoredPoint2D();
+
+ inline const void *vertexData() const { return m_data; }
+ inline const Point2D *vertexDataAsPoint2D() const;
+ inline const TexturedPoint2D *vertexDataAsTexturedPoint2D() const;
+ inline const ColoredPoint2D *vertexDataAsColoredPoint2D() const;
+
+ inline int indexType() const { return m_index_type; }
+
+ int indexCount() const { return m_index_count; }
+
+ void *indexData();
+ inline uint *indexDataAsUInt();
+ inline quint16 *indexDataAsUShort();
+
+ const void *indexData() const;
+ inline const uint *indexDataAsUInt() const;
+ inline const quint16 *indexDataAsUShort() const;
+
+ inline int attributeCount() const { return m_attributes.count; }
+ inline const Attribute *attributes() const { return m_attributes.attributes; }
+ inline int stride() const { return m_attributes.stride; }
+
+ static void updateRectGeometry(QSGGeometry *g, const QRectF &rect);
+ static void updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect, const QRectF &sourceRect);
+
+private:
+ int m_drawing_mode;
+ int m_vertex_count;
+ int m_index_count;
+ int m_index_type;
+ const AttributeSet &m_attributes;
+ void *m_data;
+ int m_index_data_offset;
+
+ void *m_reserved_pointer;
+
+ uint m_owns_data : 1;
+ uint m_reserved_bits : 31;
+
+ float m_prealloc[16];
+};
+
+inline uint *QSGGeometry::indexDataAsUInt()
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_INT);
+ return (uint *) indexData();
+}
+
+inline quint16 *QSGGeometry::indexDataAsUShort()
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_SHORT);
+ return (quint16 *) indexData();
+}
+
+inline const uint *QSGGeometry::indexDataAsUInt() const
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_INT);
+ return (uint *) indexData();
+}
+
+inline const quint16 *QSGGeometry::indexDataAsUShort() const
+{
+ Q_ASSERT(m_index_type == GL_UNSIGNED_SHORT);
+ return (quint16 *) indexData();
+}
+
+inline QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D()
+{
+ Q_ASSERT(m_attributes.count == 1);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ return (Point2D *) m_data;
+}
+
+inline QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoint2D()
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 4 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_FLOAT);
+ return (TexturedPoint2D *) m_data;
+}
+
+inline QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2D()
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float) + 4 * sizeof(char));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 4);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_UNSIGNED_BYTE);
+ return (ColoredPoint2D *) m_data;
+}
+
+inline const QSGGeometry::Point2D *QSGGeometry::vertexDataAsPoint2D() const
+{
+ Q_ASSERT(m_attributes.count == 1);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ return (const Point2D *) m_data;
+}
+
+inline const QSGGeometry::TexturedPoint2D *QSGGeometry::vertexDataAsTexturedPoint2D() const
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 4 * sizeof(float));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_FLOAT);
+ return (const TexturedPoint2D *) m_data;
+}
+
+inline const QSGGeometry::ColoredPoint2D *QSGGeometry::vertexDataAsColoredPoint2D() const
+{
+ Q_ASSERT(m_attributes.count == 2);
+ Q_ASSERT(m_attributes.stride == 2 * sizeof(float) + 4 * sizeof(char));
+ Q_ASSERT(m_attributes.attributes[0].position == 0);
+ Q_ASSERT(m_attributes.attributes[0].tupleSize == 2);
+ Q_ASSERT(m_attributes.attributes[0].type == GL_FLOAT);
+ Q_ASSERT(m_attributes.attributes[1].position == 1);
+ Q_ASSERT(m_attributes.attributes[1].tupleSize == 4);
+ Q_ASSERT(m_attributes.attributes[1].type == GL_UNSIGNED_BYTE);
+ return (const ColoredPoint2D *) m_data;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGGEOMETRY_H
diff --git a/src/declarative/scenegraph/coreapi/qsgmaterial.cpp b/src/declarative/scenegraph/coreapi/qsgmaterial.cpp
new file mode 100644
index 0000000000..4c4274419e
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmaterial.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmaterial.h"
+#include "qsgrenderer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGMaterialShader::QSGMaterialShader()
+ : m_compiled(false)
+{
+}
+
+void QSGMaterialShader::activate()
+{
+ if (!m_compiled)
+ compile();
+
+ m_program.bind();
+ char const *const *attr = attributeNames();
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ m_program.enableAttributeArray(i);
+ }
+}
+
+void QSGMaterialShader::deactivate()
+{
+ char const *const *attr = attributeNames();
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ m_program.disableAttributeArray(i);
+ }
+}
+
+void QSGMaterialShader::updateState(const RenderState &, QSGMaterial *, QSGMaterial *)
+{
+}
+
+void QSGMaterialShader::compile()
+{
+ Q_ASSERT(!m_compiled);
+
+ m_program.addShaderFromSourceCode(QGLShader::Vertex, vertexShader());
+ m_program.addShaderFromSourceCode(QGLShader::Fragment, fragmentShader());
+
+ char const *const *attr = attributeNames();
+#ifndef QT_NO_DEBUG
+ int maxVertexAttribs = 0;
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
+ for (int i = 0; attr[i]; ++i) {
+ if (i >= maxVertexAttribs) {
+ qFatal("List of attribute names is either too long or not null-terminated.\n"
+ "Maximum number of attributes on this hardware is %i.\n"
+ "Vertex shader:\n%s\n"
+ "Fragment shader:\n%s\n",
+ maxVertexAttribs, vertexShader(), fragmentShader());
+ }
+ if (*attr[i])
+ m_program.bindAttributeLocation(attr[i], i);
+ }
+#else
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ m_program.bindAttributeLocation(attr[i], i);
+ }
+#endif
+
+ if (!m_program.link()) {
+ qWarning("QSGMaterialShader: Shader compilation failed:");
+ qWarning() << m_program.log();
+ }
+
+ m_compiled = true;
+ initialize();
+}
+
+
+float QSGMaterialShader::RenderState::opacity() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->renderOpacity();
+}
+
+QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->combinedMatrix();
+}
+
+QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const
+{
+ Q_ASSERT(m_data);
+ return const_cast<QSGRenderer *>(static_cast<const QSGRenderer *>(m_data))->modelViewMatrix().top();
+}
+
+QRect QSGMaterialShader::RenderState::viewportRect() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->viewportRect();
+}
+
+QRect QSGMaterialShader::RenderState::deviceRect() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->deviceRect();
+}
+
+const QGLContext *QSGMaterialShader::RenderState::context() const
+{
+ return static_cast<const QSGRenderer *>(m_data)->glContext();
+}
+
+
+#ifndef QT_NO_DEBUG
+static int qt_material_count = 0;
+
+static void qt_print_material_count()
+{
+ qDebug("Number of leaked materials: %i", qt_material_count);
+ qt_material_count = -1;
+}
+#endif
+
+QSGMaterial::QSGMaterial()
+ : m_flags(0)
+{
+#ifndef QT_NO_DEBUG
+ ++qt_material_count;
+ static bool atexit_registered = false;
+ if (!atexit_registered) {
+ atexit(qt_print_material_count);
+ atexit_registered = true;
+ }
+#endif
+}
+
+QSGMaterial::~QSGMaterial()
+{
+#ifndef QT_NO_DEBUG
+ --qt_material_count;
+ if (qt_material_count < 0)
+ qDebug("Material destroyed after qt_print_material_count() was called.");
+#endif
+}
+
+void QSGMaterial::setFlag(Flags flags, bool set)
+{
+ if (set)
+ m_flags |= flags;
+ else
+ m_flags &= ~flags;
+}
+
+int QSGMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ return qint64(this) - qint64(other);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgmaterial.h b/src/declarative/scenegraph/coreapi/qsgmaterial.h
new file mode 100644
index 0000000000..c1513956d0
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmaterial.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MATERIAL_H
+#define MATERIAL_H
+
+#include <qglshaderprogram.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMaterial;
+
+class Q_DECLARATIVE_EXPORT QSGMaterialShader
+{
+public:
+ class Q_DECLARATIVE_EXPORT RenderState {
+ public:
+ enum DirtyState
+ {
+ DirtyMatrix = 0x0001,
+ DirtyOpacity = 0x0002
+ };
+ Q_DECLARE_FLAGS(DirtyStates, DirtyState)
+
+ inline DirtyStates dirtyState() const { return m_dirty; }
+
+ inline bool isMatrixDirty() const { return m_dirty & DirtyMatrix; }
+ inline bool isOpacityDirty() const { return m_dirty & DirtyOpacity; }
+
+ float opacity() const;
+ QMatrix4x4 combinedMatrix() const;
+ QMatrix4x4 modelViewMatrix() const;
+ QRect viewportRect() const;
+ QRect deviceRect() const;
+
+ const QGLContext *context() const;
+
+ private:
+ friend class QSGRenderer;
+ DirtyStates m_dirty;
+ const void *m_data;
+ };
+
+ QSGMaterialShader();
+
+ virtual void activate();
+ virtual void deactivate();
+ // First time a material is used, oldMaterial is null.
+ virtual void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
+ virtual char const *const *attributeNames() const = 0; // Array must end with null.
+
+protected:
+ void compile();
+ virtual void initialize() { }
+
+ virtual const char *vertexShader() const = 0;
+ virtual const char *fragmentShader() const = 0;
+
+ QGLShaderProgram m_program;
+ bool m_compiled;
+ void *m_reserved;
+};
+
+struct QSGMaterialType { };
+
+class Q_DECLARATIVE_EXPORT QSGMaterial
+{
+public:
+ enum Flag {
+ Blending = 0x0001
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QSGMaterial();
+ virtual ~QSGMaterial();
+
+ virtual QSGMaterialType *type() const = 0;
+ virtual QSGMaterialShader *createShader() const = 0;
+ virtual int compare(const QSGMaterial *other) const;
+
+ QSGMaterial::Flags flags() const { return m_flags; }
+
+protected:
+ void setFlag(Flags flags, bool set);
+
+private:
+ Flags m_flags;
+ void *m_reserved;
+ Q_DISABLE_COPY(QSGMaterial)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGMaterial::Flags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGMaterialShader::RenderState::DirtyStates)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp
new file mode 100644
index 0000000000..07ba21d17c
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.cpp
@@ -0,0 +1,380 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmatrix4x4stack.h"
+#include "qsgmatrix4x4stack_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSGMatrix4x4Stack
+ \brief The QSGMatrix4x4Stack class manages stacks of transformation matrices in GL applications.
+ \since 4.8
+ \ingroup qt3d
+ \ingroup qt3d::enablers
+
+ Transformation matrices are one of the basic building blocks of
+ 3D applications, allowing object models to be positioned, scaled,
+ rotated, and projected onto the screen.
+
+ GL systems support several standard kinds of matrices, particularly
+ modelview and projection matrices. These matrices are typically
+ organized into stacks, which allow the current matrix state to be
+ saved with push() and restored later with pop().
+
+ QSGMatrix4x4Stack assists QGLPainter with the management of matrix
+ stacks, providing operations to set and modify transformation
+ matrices in each of the standard matrix stacks.
+
+ In the following example, a standard orthographic projection matrix for a
+ view is set via the QGLPainter::projectionMatrix() stack, and
+ then a modelview matrix is set via the QGLPainter::modelViewMatrix()
+ stack to scale and translate an object prior to drawing:
+
+ \code
+ QGLPainter painter(this);
+
+ QMatrix4x4 projm;
+ projm.ortho(window->rect());
+ painter.projectionMatrix() = projm;
+
+ painter.modelViewMatrix().setToIdentity();
+ painter.modelViewMatrix().translate(-1.0f, 2.0f, 0.0f);
+ painter.modelViewMatrix().scale(0.5f);
+ \endcode
+
+ Later, the application can save the current modelview matrix state
+ and draw a different object with a different modelview matrix:
+
+ \code
+ painter.modelViewMatrix().push();
+ painter.modelViewMatrix().setToIdentity();
+ painter.modelViewMatrix().scale(2.0f);
+ \endcode
+
+ For efficiency, the matrix values are kept client-side until they
+ are needed by a QGLPainter::draw() operation. Until then, changes
+ to the matrix will not be reflected in the GL server. The application
+ can force the GL server to update the server with a call to
+ QGLPainter::update().
+
+ QSGMatrix4x4Stack is supported on all GL platforms, including OpenGL/ES 2.0
+ which doesn't support matrix stacks natively. On that platform, the
+ matrix stack is simulated in client memory. When the application
+ selects a shader program to draw under OpenGL/ES 2.0, it calls
+ top() to obtain the actual value to be set on the shader program.
+
+ \sa QGLPainter
+*/
+
+/*!
+ Creates a matrix stack.
+*/
+QSGMatrix4x4Stack::QSGMatrix4x4Stack()
+ : d_ptr(new QSGMatrix4x4StackPrivate)
+{
+}
+
+/*!
+ Destroy this matrix stack.
+*/
+QSGMatrix4x4Stack::~QSGMatrix4x4Stack()
+{
+}
+
+/*!
+ Pushes the current matrix onto the matrix stack. The matrix can
+ be restored with pop(). The new top of stack will have the
+ same value as the previous top of stack.
+
+ The depths of the traditional \c{GL_MODELVIEW} and \c{GL_PROJECTION}
+ matrix stacks in the GL server are system-dependent and easy to
+ overflow in nested rendering code using \c{glPushMatrix()}.
+ By contrast, the push() function provides an arbitrary-sized stack
+ in client memory.
+
+ \sa pop(), top()
+*/
+void QSGMatrix4x4Stack::push()
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->stack.push(d->matrix);
+}
+
+/*!
+ Pops the top-most matrix from this matrix stack and sets the
+ current matrix to the next value down. Does nothing if the
+ matrix stack contains a single entry.
+
+ \sa push()
+*/
+void QSGMatrix4x4Stack::pop()
+{
+ Q_D(QSGMatrix4x4Stack);
+ if (!d->stack.isEmpty())
+ d->matrix = d->stack.pop();
+ d->isDirty = true;
+}
+
+/*!
+ Set the matrix at the top of this matrix stack to the identity matrix.
+
+ \sa operator=()
+*/
+void QSGMatrix4x4Stack::setToIdentity()
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.setToIdentity();
+ d->isDirty = true;
+}
+
+/*!
+ Returns a const reference to the current matrix at the top of this
+ matrix stack. This is typically used to fetch the matrix so it can
+ be set on user-defined shader programs.
+
+ \sa operator=()
+*/
+const QMatrix4x4 &QSGMatrix4x4Stack::top() const
+{
+ Q_D(const QSGMatrix4x4Stack);
+ return d->matrix;
+}
+
+/*!
+ \fn QSGMatrix4x4Stack::operator const QMatrix4x4 &() const
+
+ Returns a const reference to the current matrix at the top of
+ this matrix stack.
+
+ \sa top()
+*/
+
+/*!
+ Assigns \a matrix to the matrix at the top of this matrix stack.
+
+ \sa top()
+*/
+QSGMatrix4x4Stack& QSGMatrix4x4Stack::operator=(const QMatrix4x4& matrix)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix = matrix;
+ d->isDirty = true;
+ return *this;
+}
+
+/*!
+ Multiplies the matrix at the top of this matrix stack by \a matrix.
+
+ \sa top()
+*/
+QSGMatrix4x4Stack& QSGMatrix4x4Stack::operator*=(const QMatrix4x4& matrix)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix *= matrix;
+ d->isDirty = true;
+ return *this;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that translates coordinates by (\a x, \a y, \a z). The following example
+ translates the modelview matrix by (1, -3, 0):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().translate(1.0f, -3.0f, 0.0f);
+ \endcode
+
+ \sa scale(), rotate()
+*/
+void QSGMatrix4x4Stack::translate(qreal x, qreal y, qreal z)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.translate(x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix statck by another
+ that translates coordinates by the components of \a vector.
+
+ \sa scale(), rotate()
+*/
+void QSGMatrix4x4Stack::translate(const QVector3D& vector)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.translate(vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the components \a x, \a y, and \a z.
+ The following example scales the modelview matrix by (1, 2, 1):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().scale(1.0f, 2.0f, 1.0f);
+ \endcode
+
+ \sa translate(), rotate()
+*/
+void QSGMatrix4x4Stack::scale(qreal x, qreal y, qreal z)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.scale(x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the given \a factor. The following example
+ scales the modelview matrix by a factor of 2:
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().scale(2.0f);
+ \endcode
+
+ \sa translate(), rotate()
+*/
+void QSGMatrix4x4Stack::scale(qreal factor)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.scale(factor);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that scales coordinates by the components of \a vector.
+
+ \sa translate(), rotate()
+*/
+void QSGMatrix4x4Stack::scale(const QVector3D& vector)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.scale(vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that rotates coordinates through \a angle degrees about the vector
+ (\a x, \a y, \a z). The following example rotates the modelview
+ matrix by 45 degress about the vector (1, -3, 0):
+
+ \code
+ QGLPainter painter(this);
+ painter.modelViewMatrix().rotate(45.0f, 1.0f, -3.0f, 0.0f);
+ \endcode
+
+ \sa scale(), translate()
+*/
+void QSGMatrix4x4Stack::rotate(qreal angle, qreal x, qreal y, qreal z)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.rotate(angle, x, y, z);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by another
+ that rotates coordinates through \a angle degrees about \a vector.
+
+ \sa scale(), translate()
+*/
+void QSGMatrix4x4Stack::rotate(qreal angle, const QVector3D& vector)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.rotate(angle, vector);
+ d->isDirty = true;
+}
+
+/*!
+ Multiplies the current matrix at the top of this matrix stack by the
+ \a quaternion. Thus \c {painter->modelViewMatrix().rotate(quaternion)}
+ is equivalent to the following code:
+ \code
+ QMatrix4x4 mat;
+ mat.rotate(quaternion);
+ painter->modelViewMatrix() *= mat;
+ \endcode
+ which rotates coordinates according to the given \a quaternion.
+
+ \sa scale(), translate()
+*/
+void QSGMatrix4x4Stack::rotate(const QQuaternion &quaternion)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->matrix.rotate(quaternion);
+ d->isDirty = true;
+}
+
+/*!
+ Returns true if the top of this matrix stack has been modified;
+ false otherwise.
+
+ \sa setDirty()
+*/
+bool QSGMatrix4x4Stack::isDirty() const
+{
+ Q_D(const QSGMatrix4x4Stack);
+ return d->isDirty;
+}
+
+/*!
+ Sets the \a dirty flag on this matrix stack, which indicates
+ if it has been modified.
+
+ A matrix stack may also be set to dirty by translate(),
+ scale(), operator*(), etc.
+
+ \sa isDirty()
+*/
+void QSGMatrix4x4Stack::setDirty(bool dirty)
+{
+ Q_D(QSGMatrix4x4Stack);
+ d->isDirty = dirty;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h
new file mode 100644
index 0000000000..2336598fdc
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGMATRIX4X4STACK_H
+#define QSGMATRIX4X4STACK_H
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qscopedpointer.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMatrix4x4StackPrivate;
+
+class Q_DECLARATIVE_EXPORT QSGMatrix4x4Stack
+{
+public:
+ QSGMatrix4x4Stack();
+ ~QSGMatrix4x4Stack();
+
+ const QMatrix4x4 &top() const;
+
+ void push();
+ void pop();
+
+ void setToIdentity();
+
+ void translate(qreal x, qreal y, qreal z);
+ void translate(const QVector3D& vector);
+ void scale(qreal x, qreal y, qreal z);
+ void scale(qreal factor);
+ void scale(const QVector3D& vector);
+ void rotate(qreal angle, qreal x, qreal y, qreal z);
+ void rotate(qreal angle, const QVector3D& vector);
+ void rotate(const QQuaternion &quaternion);
+
+ QSGMatrix4x4Stack& operator=(const QMatrix4x4& matrix);
+ QSGMatrix4x4Stack& operator*=(const QMatrix4x4& matrix);
+
+ operator const QMatrix4x4 &() const;
+
+ bool isDirty() const;
+ void setDirty(bool dirty);
+
+private:
+ Q_DISABLE_COPY(QSGMatrix4x4Stack)
+ Q_DECLARE_PRIVATE(QSGMatrix4x4Stack)
+
+ QScopedPointer<QSGMatrix4x4StackPrivate> d_ptr;
+
+ friend class QGLPainter;
+};
+
+inline QSGMatrix4x4Stack::operator const QMatrix4x4 &() const
+{
+ return top();
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h
new file mode 100644
index 0000000000..6e5c08ca03
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgmatrix4x4stack_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGMATRIX4X4STACK_P_H
+#define QSGMATRIX4X4STACK_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qmatrix4x4.h>
+#include <QtCore/qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGMatrix4x4StackPrivate
+{
+public:
+ QSGMatrix4x4StackPrivate() : isDirty(true) {}
+
+ QMatrix4x4 matrix;
+ QStack<QMatrix4x4> stack;
+ bool isDirty;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/scenegraph/coreapi/qsgnode.cpp b/src/declarative/scenegraph/coreapi/qsgnode.cpp
new file mode 100644
index 0000000000..5d84086457
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnode.cpp
@@ -0,0 +1,837 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgnode.h"
+#include "qsgrenderer_p.h"
+#include "qsgnodeupdater_p.h"
+#include "qsgmaterial.h"
+
+#include "limits.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_DEBUG
+static int qt_node_count = 0;
+
+static void qt_print_node_count()
+{
+ qDebug("Number of leaked nodes: %i", qt_node_count);
+ qt_node_count = -1;
+}
+#endif
+
+/*!
+ \class QSGNode
+ \bried The QSGNode class is the base class for all nodes in the scene graph.
+
+ The QSGNode class can be used as a child container. Children are added with
+ the appendChildNode(), prependChildNode(), insertChildNodeBefore() and
+ insertChildNodeAfter(). Ordering is important as nodes are rendered in
+ order. Actually, the scene may reorder nodes freely, but the resulting visual
+ order is still guaranteed.
+
+ If nodes change every frame, the preprocess() function can be used to
+ apply changes to a node for every frame its rendered. The use of preprocess()
+ must be explicitly enabled by setting the QSGNode::UsePreprocess flag
+ on the node.
+
+ The virtual isSubtreeBlocked() function can be used to disable a subtree all
+ together. Nodes in a blocked subtree will not be preprocessed() and not
+ rendered.
+
+ Anything related to QSGNode should happen on the scene graph rendering thread.
+ */
+
+QSGNode::QSGNode()
+ : m_parent(0)
+ , m_nodeFlags(OwnedByParent)
+ , m_flags(0)
+{
+#ifndef QT_NO_DEBUG
+ ++qt_node_count;
+ static bool atexit_registered = false;
+ if (!atexit_registered) {
+ atexit(qt_print_node_count);
+ atexit_registered = true;
+ }
+#endif
+
+}
+
+QSGNode::~QSGNode()
+{
+#ifndef QT_NO_DEBUG
+ --qt_node_count;
+ if (qt_node_count < 0)
+ qDebug("Material destroyed after qt_print_node_count() was called.");
+#endif
+ destroy();
+}
+
+
+/*!
+ \fn void QSGNode::preprocess()
+
+ Override this function to do processing on the node before it is rendered.
+
+ Preprocessing needs to be explicitly enabled by setting the flag
+ QSGNode::UsePreprocess. The flag needs to be set before the node is added
+ to the scene graph and will cause the preprocess() function to be called
+ for every frame the node is rendered.
+
+ The preprocess function is called before the update pass that propegates
+ opacity and transformations through the scene graph. That means that
+ functions like QSGOpacityNode::combinedOpacity() and
+ QSGTransformNode::combinedMatrix() will not contain up-to-date values.
+ If such values are changed during the preprocess, these changes will be
+ propegated through the scene graph before it is rendered.
+
+ \warning Beware of deleting nodes while they are being preprocessed. It is
+ possible, with a small performance hit, to delete a single node during its
+ own preprocess call. Deleting a subtree which has nodes that also use
+ preprocessing may result in a segmentation fault. This is done for
+ performance reasons.
+ */
+
+
+
+
+/*!
+ \fn bool QSGNode::isSubtreeBlocked() const
+
+ Returns whether this node and its subtree is available for use.
+
+ Blocked subtrees will not get their dirty states updated and they
+ will not be rendered.
+
+ The QSGOpacityNode will return a blocked subtree when accumulated opacity
+ is 0, for instance.
+ */
+
+
+void QSGNode::destroy()
+{
+ if (m_parent) {
+ m_parent->removeChildNode(this);
+ Q_ASSERT(m_parent == 0);
+ }
+ for (int ii = m_children.count() - 1; ii >= 0; --ii) {
+ QSGNode *child = m_children.at(ii);
+ removeChildNode(child);
+ Q_ASSERT(child->m_parent == 0);
+ if (child->flags() & OwnedByParent)
+ delete child;
+ }
+ Q_ASSERT(m_children.isEmpty());
+}
+
+void QSGNode::prependChildNode(QSGNode *node)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::prependChildNode", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::prependChildNode", "QSGNode already has a parent");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::prependChildNode", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::prependChildNode", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ m_children.prepend(node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+void QSGNode::appendChildNode(QSGNode *node)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::appendChildNode", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::appendChildNode", "QSGNode already has a parent");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::appendChildNode", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::appendChildNode", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ m_children.append(node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+void QSGNode::insertChildNodeBefore(QSGNode *node, QSGNode *before)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeBefore", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeBefore", "QSGNode already has a parent");
+ Q_ASSERT_X(node->type() != RootNodeType, "QSGNode::insertChildNodeBefore", "RootNodes cannot be children of other nodes");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeBefore", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ int idx = before?m_children.indexOf(before):-1;
+ if (idx == -1)
+ m_children.append(node);
+ else
+ m_children.insert(idx, node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+void QSGNode::insertChildNodeAfter(QSGNode *node, QSGNode *after)
+{
+ Q_ASSERT_X(!m_children.contains(node), "QSGNode::insertChildNodeAfter", "QSGNode is already a child!");
+ Q_ASSERT_X(!node->m_parent, "QSGNode::insertChildNodeAfter", "QSGNode already has a parent");
+ Q_ASSERT_X(node->type() != RootNodeType, "QSGNode::insertChildNodeAfter", "RootNodes cannot be children of other nodes");
+
+#ifndef QT_NO_DEBUG
+ if (node->type() == QSGNode::GeometryNodeType) {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(node);
+ Q_ASSERT_X(g->material(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing material");
+ Q_ASSERT_X(g->geometry(), "QSGNode::insertChildNodeAfter", "QSGGeometryNode is missing geometry");
+ }
+#endif
+
+ int idx = after?m_children.indexOf(after):-1;
+ if (idx == -1)
+ m_children.append(node);
+ else
+ m_children.insert(idx + 1, node);
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+void QSGNode::removeChildNode(QSGNode *node)
+{
+ Q_ASSERT(m_children.contains(node));
+ Q_ASSERT(node->parent() == this);
+
+ m_children.removeOne(node);
+
+ node->markDirty(DirtyNodeRemoved);
+ node->m_parent = 0;
+}
+
+
+/*!
+ Sets the flag \a f on this node if \a enabled is true;
+ otherwise clears the flag.
+
+ \sa flags()
+*/
+
+void QSGNode::setFlag(Flag f, bool enabled)
+{
+ if (enabled)
+ m_nodeFlags |= f;
+ else
+ m_nodeFlags &= ~f;
+}
+
+
+/*!
+ Sets the flags \a f on this node if \a enabled is true;
+ otherwise clears the flags.
+
+ \sa flags()
+*/
+
+void QSGNode::setFlags(Flags f, bool enabled)
+{
+ if (enabled)
+ m_nodeFlags |= f;
+ else
+ m_nodeFlags &= ~f;
+}
+
+
+void QSGNode::markDirty(DirtyFlags flags)
+{
+ m_flags |= (flags & DirtyPropagationMask);
+
+ DirtyFlags subtreeFlags = DirtyFlags((flags & DirtyPropagationMask) << 16);
+ QSGNode *p = m_parent;
+ while (p) {
+ p->m_flags |= subtreeFlags;
+ if (p->type() == RootNodeType)
+ static_cast<QSGRootNode *>(p)->notifyNodeChange(this, flags);
+ p = p->m_parent;
+ }
+}
+
+QSGBasicGeometryNode::QSGBasicGeometryNode()
+ : m_geometry(0)
+ , m_matrix(0)
+ , m_clip_list(0)
+{
+}
+
+QSGBasicGeometryNode::~QSGBasicGeometryNode()
+{
+ destroy();
+ if (flags() & OwnsGeometry)
+ delete m_geometry;
+}
+
+void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry)
+{
+ if (flags() & OwnsGeometry)
+ delete m_geometry;
+ m_geometry = geometry;
+ markDirty(DirtyGeometry);
+}
+
+
+QSGGeometryNode::QSGGeometryNode()
+ : m_render_order(0)
+ , m_material(0)
+ , m_opaque_material(0)
+ , m_opacity(1)
+{
+}
+
+QSGGeometryNode::~QSGGeometryNode()
+{
+ destroy();
+ if (flags() & OwnsMaterial)
+ delete m_material;
+ if (flags() & OwnsOpaqueMaterial)
+ delete m_opaque_material;
+}
+
+/*!
+ Sets the render order of this node to be \a order.
+
+ GeometryNodes are rendered in an order that visually looks like
+ low order nodes are rendered prior to high order nodes. For opaque
+ geometry there is little difference as z-testing will handle
+ the discard, but for translucent objects, the rendering should
+ normally be specified in the order of back-to-front.
+
+ The default render order is 0.
+
+ \internal
+ */
+void QSGGeometryNode::setRenderOrder(int order)
+{
+ m_render_order = order;
+}
+
+
+
+/*!
+ Sets the material of this geometry node to \a material.
+
+ GeometryNodes must have a material before they can be added to the
+ scene graph.
+ */
+void QSGGeometryNode::setMaterial(QSGMaterial *material)
+{
+ if (flags() & OwnsMaterial)
+ delete m_material;
+ m_material = material;
+#ifndef QT_NO_DEBUG
+ if (m_material != 0 && m_opaque_material == m_material)
+ qWarning("QSGGeometryNode: using same material for both opaque and translucent");
+#endif
+ markDirty(DirtyMaterial);
+}
+
+
+
+/*!
+ Sets the opaque material of this geometry to \a material.
+
+ The opaque material will be preferred by the renderer over the
+ default material, as returned by the material() function, if
+ it is not null and the geometry item has an inherited opacity of
+ 1.
+
+ The opaqueness refers to scene graph opacity, the material is still
+ allowed to set QSGMaterial::Blending to true and draw transparent
+ pixels.
+ */
+void QSGGeometryNode::setOpaqueMaterial(QSGMaterial *material)
+{
+ if (flags() & OwnsOpaqueMaterial)
+ delete m_opaque_material;
+ m_opaque_material = material;
+#ifndef QT_NO_DEBUG
+ if (m_opaque_material != 0 && m_opaque_material == m_material)
+ qWarning("QSGGeometryNode: using same material for both opaque and translucent");
+#endif
+
+ markDirty(DirtyMaterial);
+}
+
+
+
+/*!
+ Returns the material which should currently be used for geometry node.
+
+ If the inherited opacity of the node is 1 and there is an opaque material
+ set on this node, it will be returned; otherwise, the default material
+ will be returned.
+
+ \warning This function requires the scene graph above this item to be
+ completely free of dirty states, so it can only be called during rendering
+
+ \internal
+
+ \sa setMaterial, setOpaqueMaterial
+ */
+QSGMaterial *QSGGeometryNode::activeMaterial() const
+{
+ Q_ASSERT_X(dirtyFlags() == 0, "QSGGeometryNode::activeMaterial()", "function assumes that all dirty states are cleaned up");
+ if (m_opaque_material && m_opacity > 0.999)
+ return m_opaque_material;
+ return m_material;
+}
+
+
+/*!
+ Sets the inherited opacity of this geometry to \a opacity.
+
+ This function is meant to be called by the node preprocessing
+ prior to rendering the tree, so it will not mark the tree as
+ dirty.
+
+ \internal
+ */
+void QSGGeometryNode::setInheritedOpacity(qreal opacity)
+{
+ Q_ASSERT(opacity >= 0 && opacity <= 1);
+ m_opacity = opacity;
+}
+
+
+
+QSGClipNode::QSGClipNode()
+{
+}
+
+QSGClipNode::~QSGClipNode()
+{
+ destroy();
+}
+
+/*!
+ Sets whether this clip node has a rectangular clip to \a rectHint.
+ */
+void QSGClipNode::setIsRectangular(bool rectHint)
+{
+ m_is_rectangular = rectHint;
+}
+
+
+/*!
+ Sets the clip rect of this clip node to \a rect.
+
+ When a rectangular clip is set in combination with setIsRectangular
+ the renderer may in some cases use a more optimal clip method.
+ */
+void QSGClipNode::setClipRect(const QRectF &rect)
+{
+ m_clip_rect = rect;
+}
+
+
+QSGTransformNode::QSGTransformNode()
+{
+}
+
+QSGTransformNode::~QSGTransformNode()
+{
+ destroy();
+}
+
+void QSGTransformNode::setMatrix(const QMatrix4x4 &matrix)
+{
+ m_matrix = matrix;
+ markDirty(DirtyMatrix);
+}
+
+
+/*!
+ Sets the combined matrix of this matrix to \a transform.
+
+ This function is meant to be called by the node preprocessing
+ prior to rendering the tree, so it will not mark the tree as
+ dirty.
+
+ \internal
+ */
+void QSGTransformNode::setCombinedMatrix(const QMatrix4x4 &matrix)
+{
+ m_combined_matrix = matrix;
+}
+
+
+
+QSGRootNode::~QSGRootNode()
+{
+ while (!m_renderers.isEmpty())
+ m_renderers.last()->setRootNode(0);
+ destroy();
+}
+
+
+void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyFlags flags)
+{
+ for (int i=0; i<m_renderers.size(); ++i) {
+ m_renderers.at(i)->nodeChanged(node, flags);
+ }
+}
+
+/*!
+ Constructs an opacity node with a default opacity of 1.
+
+ Opacity accumulate downwards in the scene graph so a node with two
+ QSGOpacityNode instances above it, both with opacity of 0.5, will have
+ effective opacity of 0.25.
+
+ The default opacity of nodes is 1.
+ */
+QSGOpacityNode::QSGOpacityNode()
+ : m_opacity(1)
+ , m_combined_opacity(1)
+{
+}
+
+
+QSGOpacityNode::~QSGOpacityNode()
+{
+ destroy();
+}
+
+
+/*!
+ Sets the opacity of this node to \a opacity.
+
+ Before rendering the graph, the renderer will do an update pass
+ over the subtree to propegate the opacity to its children.
+
+ The value will be bounded to the range 0 to 1.
+ */
+void QSGOpacityNode::setOpacity(qreal opacity)
+{
+ opacity = qBound<qreal>(0, opacity, 1);
+ if (m_opacity == opacity)
+ return;
+ m_opacity = opacity;
+ markDirty(DirtyOpacity);
+}
+
+
+/*!
+ Sets the combined opacity of this node to \a opacity.
+
+ This function is meant to be called by the node preprocessing
+ prior to rendering the tree, so it will not mark the tree as
+ dirty.
+
+ \internal
+ */
+void QSGOpacityNode::setCombinedOpacity(qreal opacity)
+{
+ m_combined_opacity = opacity;
+}
+
+
+bool QSGOpacityNode::isSubtreeBlocked() const
+{
+ return m_combined_opacity < 0.001;
+}
+
+
+QSGNodeVisitor::~QSGNodeVisitor()
+{
+
+}
+
+
+void QSGNodeVisitor::visitNode(QSGNode *n)
+{
+ switch (n->type()) {
+ case QSGNode::TransformNodeType: {
+ QSGTransformNode *t = static_cast<QSGTransformNode *>(n);
+ enterTransformNode(t);
+ visitChildren(t);
+ leaveTransformNode(t);
+ break; }
+ case QSGNode::GeometryNodeType: {
+ QSGGeometryNode *g = static_cast<QSGGeometryNode *>(n);
+ enterGeometryNode(g);
+ visitChildren(g);
+ leaveGeometryNode(g);
+ break; }
+ case QSGNode::ClipNodeType: {
+ QSGClipNode *c = static_cast<QSGClipNode *>(n);
+ enterClipNode(c);
+ visitChildren(c);
+ leaveClipNode(c);
+ break; }
+ case QSGNode::OpacityNodeType: {
+ QSGOpacityNode *o = static_cast<QSGOpacityNode *>(n);
+ enterOpacityNode(o);
+ visitChildren(o);
+ leaveOpacityNode(o);
+ break; }
+ default:
+ visitChildren(n);
+ break;
+ }
+}
+
+void QSGNodeVisitor::visitChildren(QSGNode *n)
+{
+ int count = n->childCount();
+ for (int i=0; i<count; ++i) {
+ visitNode(n->childAtIndex(i));
+ }
+}
+
+
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const QSGGeometryNode *n)
+{
+ if (!n) {
+ d << "QSGGeometryNode(null)";
+ return d;
+ }
+ d << "QSGGeometryNode(" << hex << (void *) n << dec;
+
+ const QSGGeometry *g = n->geometry();
+
+ if (!g) {
+ d << "no geometry";
+ } else {
+
+ switch (g->drawingMode()) {
+ case GL_TRIANGLE_STRIP: d << "strip"; break;
+ case GL_TRIANGLE_FAN: d << "fan"; break;
+ case GL_TRIANGLES: d << "triangles"; break;
+ default: break;
+ }
+
+ d << g->vertexCount();
+
+ if (g->attributeCount() > 0 && g->attributes()->type == GL_FLOAT) {
+ float x1 = 1e10, x2 = -1e10, y1=1e10, y2=-1e10;
+ int stride = g->stride();
+ for (int i = 0; i < g->vertexCount(); ++i) {
+ float x = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[0];
+ float y = ((float *)((char *)const_cast<QSGGeometry *>(g)->vertexData() + i * stride))[1];
+
+ x1 = qMin(x1, x);
+ x2 = qMax(x2, x);
+ y1 = qMin(y1, y);
+ y2 = qMax(y2, y);
+ }
+
+ d << "x1=" << x1 << "y1=" << y1 << "x2=" << x2 << "y2=" << y2;
+ }
+ }
+
+ d << "order=" << n->renderOrder();
+ if (n->material())
+ d << "effect=" << n->material() << "type=" << n->material()->type();
+
+
+ d << ")";
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec;
+ return d;
+}
+
+QDebug operator<<(QDebug d, const QSGClipNode *n)
+{
+ if (!n) {
+ d << "QSGClipNode(null)";
+ return d;
+ }
+ d << "QSGClipNode(" << hex << (void *) n << dec;
+
+ if (n->childCount())
+ d << "children=" << n->childCount();
+
+ d << "is rect?" << (n->isRectangular() ? "yes" : "no");
+
+ d << ")";
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+ return d;
+}
+
+QDebug operator<<(QDebug d, const QSGTransformNode *n)
+{
+ if (!n) {
+ d << "QSGTransformNode(null)";
+ return d;
+ }
+ const QMatrix4x4 m = n->matrix();
+ d << "QSGTransformNode(";
+ d << hex << (void *) n << dec;
+ if (m.isIdentity())
+ d << "identity";
+ else if (m.determinant() == 1 && m(0, 0) == 1 && m(1, 1) == 1 && m(2, 2) == 1)
+ d << "translate" << m(0, 3) << m(1, 3) << m(2, 3);
+ else
+ d << "det=" << n->matrix().determinant();
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+ d << ")";
+ return d;
+}
+
+QDebug operator<<(QDebug d, const QSGOpacityNode *n)
+{
+ if (!n) {
+ d << "QSGOpacityNode(null)";
+ return d;
+ }
+ d << "QSGOpacityNode(";
+ d << hex << (void *) n << dec;
+ d << "opacity=" << n->opacity()
+ << "combined=" << n->combinedOpacity()
+ << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << "dirty=" << hex << (int) n->dirtyFlags() << dec;
+ d << ")";
+ return d;
+}
+
+
+QDebug operator<<(QDebug d, const QSGRootNode *n)
+{
+ if (!n) {
+ d << "QSGRootNode(null)";
+ return d;
+ }
+ d << "QSGRootNode" << hex << (void *) n << "dirty=" << (int) n->dirtyFlags() << dec
+ << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << ")";
+ return d;
+}
+
+
+
+QDebug operator<<(QDebug d, const QSGNode *n)
+{
+ if (!n) {
+ d << "QSGNode(null)";
+ return d;
+ }
+ switch (n->type()) {
+ case QSGNode::GeometryNodeType:
+ d << static_cast<const QSGGeometryNode *>(n);
+ break;
+ case QSGNode::TransformNodeType:
+ d << static_cast<const QSGTransformNode *>(n);
+ break;
+ case QSGNode::ClipNodeType:
+ d << static_cast<const QSGClipNode *>(n);
+ break;
+ case QSGNode::RootNodeType:
+ d << static_cast<const QSGRootNode *>(n);
+ break;
+ case QSGNode::OpacityNodeType:
+ d << static_cast<const QSGOpacityNode *>(n);
+ break;
+ default:
+ d << "QSGNode(" << hex << (void *) n << dec
+ << "dirty=" << hex << (int) n->dirtyFlags() << dec
+ << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << ")";
+ break;
+ }
+ return d;
+}
+
+void QSGNodeDumper::dump(QSGNode *n)
+{
+ QSGNodeDumper dump;
+ dump.visitNode(n);
+}
+
+void QSGNodeDumper::visitNode(QSGNode *n)
+{
+ if (n->isSubtreeBlocked())
+ return;
+ qDebug() << QString(m_indent * 2, QLatin1Char(' ')) << n;
+ QSGNodeVisitor::visitNode(n);
+}
+
+void QSGNodeDumper::visitChildren(QSGNode *n)
+{
+ ++m_indent;
+ QSGNodeVisitor::visitChildren(n);
+ --m_indent;
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgnode.h b/src/declarative/scenegraph/coreapi/qsgnode.h
new file mode 100644
index 0000000000..d6700af32e
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnode.h
@@ -0,0 +1,363 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NODE_H
+#define NODE_H
+
+#include "qsggeometry.h"
+#include <QtGui/QMatrix4x4>
+
+#include <float.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+#define QML_RUNTIME_TESTING
+
+class QSGRenderer;
+
+class QSGNode;
+class QSGRootNode;
+class QSGGeometryNode;
+class QSGTransformNode;
+class QSGClipNode;
+
+class Q_DECLARATIVE_EXPORT QSGNode
+{
+public:
+ enum NodeType {
+ BasicNodeType,
+ RootNodeType,
+ GeometryNodeType,
+ TransformNodeType,
+ ClipNodeType,
+ OpacityNodeType,
+ UserNodeType = 1024
+ };
+
+ enum DirtyFlag {
+ DirtyMatrix = 0x0001,
+ DirtyClipList = 0x0002,
+ DirtyNodeAdded = 0x0004,
+ DirtyNodeRemoved = 0x0008,
+ DirtyGeometry = 0x0010,
+ DirtyRenderOrder = 0x0020,
+ DirtyMaterial = 0x0100,
+ DirtyOpacity = 0x0200,
+ DirtyAll = 0xffff,
+
+ DirtyPropagationMask = DirtyMatrix
+ | DirtyClipList
+ | DirtyNodeAdded
+ | DirtyOpacity,
+
+ };
+ Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
+
+ enum Flag {
+ // Lower 16 bites reserved for general node
+ OwnedByParent = 0x0001,
+ UsePreprocess = 0x0002,
+ ChildrenDoNotOverlap = 0x0004,
+
+ // Upper 16 bits reserved for node subclasses
+
+ // QSGBasicGeometryNode
+ OwnsGeometry = 0x00010000,
+ OwnsMaterial = 0x00020000,
+ OwnsOpaqueMaterial = 0x00040000
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QSGNode();
+ virtual ~QSGNode();
+
+ QSGNode *parent() const { return m_parent; }
+
+ void removeChildNode(QSGNode *node);
+ void prependChildNode(QSGNode *node);
+ void appendChildNode(QSGNode *node);
+ void insertChildNodeBefore(QSGNode *node, QSGNode *before);
+ void insertChildNodeAfter(QSGNode *node, QSGNode *after);
+
+ int childCount() const { return m_children.size(); }
+ QSGNode *childAtIndex(int i) const { return m_children.at(i); }
+
+ virtual NodeType type() const { return BasicNodeType; }
+
+ void clearDirty() { m_flags = 0; }
+ void markDirty(DirtyFlags flags);
+ DirtyFlags dirtyFlags() const { return m_flags; }
+
+ virtual bool isSubtreeBlocked() const { return false; }
+
+ Flags flags() const { return m_nodeFlags; }
+ void setFlag(Flag, bool = true);
+ void setFlags(Flags, bool = true);
+
+ virtual void preprocess() { }
+
+#ifdef QML_RUNTIME_TESTING
+ QString description;
+#endif
+
+protected:
+ // When a node is destroyed, it will detach from the scene graph and the renderer will be
+ // notified about the change. If the node is detached in the base node's destructor, the
+ // renderer can't check what type the node originally was because the node's type() method is
+ // virtual and will return the base node type. The renderer might therefore react incorrectly
+ // to the change. There are a few of ways I can think of to solve the problem:
+ // - The renderer must take into account that the notify method might be called from a node's
+ // destructor.
+ // - The node can have a type property that is set in the constructor.
+ // - All the node destructors must call a common destroy method.
+ // I choose the third option since that will allow the renderer to treat the nodes as their
+ // proper types.
+
+ void destroy();
+
+private:
+ QSGNode *m_parent;
+ QList<QSGNode *> m_children;
+
+ Flags m_nodeFlags;
+ DirtyFlags m_flags;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGNode::DirtyFlags);
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGNode::Flags);
+
+class Q_DECLARATIVE_EXPORT QSGBasicGeometryNode : public QSGNode
+{
+public:
+// enum UsagePattern {
+// Static,
+// Dynamic,
+// Stream
+// };
+// void setUsagePattern(UsagePattern pattern);
+// UsagePattern usagePattern() const { return m_pattern; }
+
+ QSGBasicGeometryNode();
+ ~QSGBasicGeometryNode();
+
+ void setGeometry(QSGGeometry *geometry);
+ const QSGGeometry *geometry() const { return m_geometry; }
+ QSGGeometry *geometry() { return m_geometry; }
+
+ const QMatrix4x4 *matrix() const { return m_matrix; }
+ const QSGClipNode *clipList() const { return m_clip_list; }
+
+private:
+ friend class QSGNodeUpdater;
+ QSGGeometry *m_geometry;
+
+ int m_reserved_start_index;
+ int m_reserved_end_index;
+
+ const QMatrix4x4 *m_matrix;
+ const QSGClipNode *m_clip_list;
+
+// UsagePattern m_pattern;
+};
+
+class QSGMaterial;
+
+class Q_DECLARATIVE_EXPORT QSGGeometryNode : public QSGBasicGeometryNode
+{
+public:
+ QSGGeometryNode();
+ ~QSGGeometryNode();
+
+ void setMaterial(QSGMaterial *material);
+ QSGMaterial *material() const { return m_material; }
+
+ void setOpaqueMaterial(QSGMaterial *material);
+ QSGMaterial *opaqueMaterial() const { return m_opaque_material; }
+
+ QSGMaterial *activeMaterial() const;
+
+ virtual NodeType type() const { return GeometryNodeType; }
+
+ void setRenderOrder(int order);
+ int renderOrder() const { return m_render_order; }
+
+ void setInheritedOpacity(qreal opacity);
+ qreal inheritedOpacity() const { return m_opacity; }
+
+private:
+ friend class QSGNodeUpdater;
+
+ int m_render_order;
+ QSGMaterial *m_material;
+ QSGMaterial *m_opaque_material;
+
+ qreal m_opacity;
+};
+
+class Q_DECLARATIVE_EXPORT QSGClipNode : public QSGBasicGeometryNode
+{
+public:
+ QSGClipNode();
+ ~QSGClipNode();
+
+ virtual NodeType type() const { return ClipNodeType; }
+
+ void setIsRectangular(bool rectHint);
+ bool isRectangular() const { return m_is_rectangular; }
+
+ void setClipRect(const QRectF &);
+ QRectF clipRect() const { return m_clip_rect; }
+
+private:
+ uint m_is_rectangular : 1;
+ uint m_reserved : 31;
+
+ QRectF m_clip_rect;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGTransformNode : public QSGNode
+{
+public:
+ QSGTransformNode();
+ ~QSGTransformNode();
+
+ virtual NodeType type() const { return TransformNodeType; }
+
+ void setMatrix(const QMatrix4x4 &matrix);
+ const QMatrix4x4 &matrix() const { return m_matrix; }
+
+ void setCombinedMatrix(const QMatrix4x4 &matrix);
+ const QMatrix4x4 &combinedMatrix() const { return m_combined_matrix; }
+
+private:
+ QMatrix4x4 m_matrix;
+ QMatrix4x4 m_combined_matrix;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGRootNode : public QSGNode
+{
+public:
+ ~QSGRootNode();
+ NodeType type() const { return RootNodeType; }
+
+private:
+ void notifyNodeChange(QSGNode *node, DirtyFlags flags);
+
+ friend class QSGRenderer;
+ friend class QSGNode;
+ friend class QSGGeometryNode;
+
+ QList<QSGRenderer *> m_renderers;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGOpacityNode : public QSGNode
+{
+public:
+ QSGOpacityNode();
+ ~QSGOpacityNode();
+
+ void setOpacity(qreal opacity);
+ qreal opacity() const { return m_opacity; }
+
+ void setCombinedOpacity(qreal opacity);
+ qreal combinedOpacity() const { return m_combined_opacity; }
+
+ virtual QSGNode::NodeType type() const { return OpacityNodeType; }
+
+ bool isSubtreeBlocked() const;
+
+
+private:
+ qreal m_opacity;
+ qreal m_combined_opacity;
+};
+
+class Q_DECLARATIVE_EXPORT QSGNodeVisitor {
+public:
+ virtual ~QSGNodeVisitor();
+
+protected:
+ virtual void enterTransformNode(QSGTransformNode *) {}
+ virtual void leaveTransformNode(QSGTransformNode *) {}
+ virtual void enterClipNode(QSGClipNode *) {}
+ virtual void leaveClipNode(QSGClipNode *) {}
+ virtual void enterGeometryNode(QSGGeometryNode *) {}
+ virtual void leaveGeometryNode(QSGGeometryNode *) {}
+ virtual void enterOpacityNode(QSGOpacityNode *) {}
+ virtual void leaveOpacityNode(QSGOpacityNode *) {}
+ virtual void visitNode(QSGNode *n);
+ virtual void visitChildren(QSGNode *n);
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGGeometryNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGTransformNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGOpacityNode *n);
+Q_DECLARATIVE_EXPORT QDebug operator<<(QDebug, const QSGRootNode *n);
+
+class QSGNodeDumper : public QSGNodeVisitor {
+
+public:
+ static void dump(QSGNode *n);
+
+ QSGNodeDumper() : m_indent(0) {}
+ void visitNode(QSGNode *n);
+ void visitChildren(QSGNode *n);
+
+private:
+ int m_indent;
+};
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // NODE_H
diff --git a/src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp b/src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp
new file mode 100644
index 0000000000..d81248be3d
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnodeupdater.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgnodeupdater_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// #define QSG_UPDATER_DEBUG
+
+QSGNodeUpdater::QSGNodeUpdater()
+ : m_current_clip(0)
+ , m_force_update(0)
+{
+ m_opacity_stack.push(1);
+}
+
+void QSGNodeUpdater::updateStates(QSGNode *n)
+{
+ m_current_clip = 0;
+ m_force_update = 0;
+
+ Q_ASSERT(m_opacity_stack.size() == 1); // The one we added in the constructr...
+ // Q_ASSERT(m_matrix_stack.isEmpty()); ### no such function?
+ Q_ASSERT(m_combined_matrix_stack.isEmpty());
+
+ visitNode(n);
+}
+
+/*!
+ \fn void QSGNodeUpdater::setToplevelOpacity(qreal opacity)
+
+ Sets the toplevel opacity that will be multiplied with the
+
+ The default opacity is 1. Any other value will cause artifacts, and is
+ primarily useful for debug purposes.
+
+ The changing the value during an update pass will have undefined results
+ */
+
+/*!
+ \fn qreal QSGNodeUpdater::toplevelOpacity() const
+
+ Returns the toplevel opacity for the node updater. The default
+ value is 1.
+ */
+
+
+/*!
+ Returns true if \a node is has something that blocks it in the chain from
+ \a node to \a root doing a full state update pass.
+
+ This function does not process dirty states, simply does a simple traversion
+ up to the top.
+
+ The function assumes that \a root exists in the parent chain of \a node.
+ */
+
+bool QSGNodeUpdater::isNodeBlocked(QSGNode *node, QSGNode *root) const
+{
+ qreal opacity = 1;
+ while (node != root) {
+ if (node->type() == QSGNode::OpacityNodeType) {
+ opacity *= static_cast<QSGOpacityNode *>(node)->opacity();
+ if (opacity < 0.001)
+ return true;
+ }
+ node = node->parent();
+
+ Q_ASSERT_X(node, "QSGNodeUpdater::isNodeBlocked", "node is not in the subtree of root");
+ }
+
+ return false;
+}
+
+
+void QSGNodeUpdater::enterTransformNode(QSGTransformNode *t)
+{
+ if (t->dirtyFlags() & QSGNode::DirtyMatrix)
+ ++m_force_update;
+
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter transform:" << t << "force=" << m_force_update;
+#endif
+
+ if (!t->matrix().isIdentity()) {
+ m_combined_matrix_stack.push(&t->combinedMatrix());
+
+ m_matrix_stack.push();
+ m_matrix_stack *= t->matrix();
+ }
+
+ t->setCombinedMatrix(m_matrix_stack.top());
+}
+
+
+void QSGNodeUpdater::leaveTransformNode(QSGTransformNode *t)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "leave transform:" << t;
+#endif
+
+ if (t->dirtyFlags() & QSGNode::DirtyMatrix)
+ --m_force_update;
+
+ if (!t->matrix().isIdentity()) {
+ m_matrix_stack.pop();
+ m_combined_matrix_stack.pop();
+ }
+
+}
+
+
+void QSGNodeUpdater::enterClipNode(QSGClipNode *c)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter clip:" << c;
+#endif
+
+ if (c->dirtyFlags() & QSGNode::DirtyClipList) {
+ ++m_force_update;
+ }
+
+ c->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.top();
+ c->m_clip_list = m_current_clip;
+ m_current_clip = c;
+}
+
+
+void QSGNodeUpdater::leaveClipNode(QSGClipNode *c)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "leave clip:" << c;
+#endif
+
+ if (c->dirtyFlags() & QSGNode::DirtyClipList) {
+ --m_force_update;
+ }
+
+ m_current_clip = c->m_clip_list;
+}
+
+
+void QSGNodeUpdater::enterGeometryNode(QSGGeometryNode *g)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter geometry:" << g;
+#endif
+
+ g->m_matrix = m_combined_matrix_stack.isEmpty() ? 0 : m_combined_matrix_stack.top();
+ g->m_clip_list = m_current_clip;
+ g->setInheritedOpacity(m_opacity_stack.top());
+}
+
+void QSGNodeUpdater::enterOpacityNode(QSGOpacityNode *o)
+{
+ if (o->dirtyFlags() & QSGNode::DirtyOpacity)
+ ++m_force_update;
+
+ qreal opacity = m_opacity_stack.top() * o->opacity();
+ o->setCombinedOpacity(opacity);
+ m_opacity_stack.push(opacity);
+
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter opacity" << o;
+#endif
+}
+
+void QSGNodeUpdater::leaveOpacityNode(QSGOpacityNode *o)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "leave opacity" << o;
+#endif
+ if (o->flags() & QSGNode::DirtyOpacity)
+ --m_force_update;
+
+ m_opacity_stack.pop();
+}
+
+void QSGNodeUpdater::visitChildren(QSGNode *n)
+{
+ if (!n->isSubtreeBlocked())
+ QSGNodeVisitor::visitChildren(n);
+}
+
+void QSGNodeUpdater::visitNode(QSGNode *n)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter:" << n;
+#endif
+
+ if (n->dirtyFlags() || m_force_update) {
+ bool forceUpdate = n->dirtyFlags() & (QSGNode::DirtyNodeAdded);
+ if (forceUpdate)
+ ++m_force_update;
+
+ QSGNodeVisitor::visitNode(n);
+
+ if (forceUpdate)
+ --m_force_update;
+
+ n->clearDirty();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h b/src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h
new file mode 100644
index 0000000000..518cf9eff9
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgnodeupdater_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NODEUPDATER_P_H
+#define NODEUPDATER_P_H
+
+#include "qsgnode.h"
+#include "qsgmatrix4x4stack.h"
+#include <qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_DECLARATIVE_EXPORT QSGNodeUpdater : public QSGNodeVisitor
+{
+public:
+ QSGNodeUpdater();
+
+ virtual void updateStates(QSGNode *n);
+ virtual bool isNodeBlocked(QSGNode *n, QSGNode *root) const;
+
+ void setToplevelOpacity(qreal alpha) { m_opacity_stack.top() = alpha; }
+ qreal toplevelOpacity() const { return m_opacity_stack.top(); }
+
+protected:
+ void enterTransformNode(QSGTransformNode *);
+ void leaveTransformNode(QSGTransformNode *);
+ void enterClipNode(QSGClipNode *c);
+ void leaveClipNode(QSGClipNode *c);
+ void enterOpacityNode(QSGOpacityNode *o);
+ void leaveOpacityNode(QSGOpacityNode *o);
+ void enterGeometryNode(QSGGeometryNode *);
+
+ void visitNode(QSGNode *n);
+ void visitChildren(QSGNode *n);
+
+
+ QSGMatrix4x4Stack m_matrix_stack;
+ QStack<const QMatrix4x4 *> m_combined_matrix_stack;
+ QStack<qreal> m_opacity_stack;
+ const QSGClipNode *m_current_clip;
+
+ int m_force_update;
+
+ qreal m_toplevel_alpha;
+};
+
+QT_END_NAMESPACE
+
+#endif // NODEUPDATER_P_H
diff --git a/src/declarative/scenegraph/coreapi/qsgrenderer.cpp b/src/declarative/scenegraph/coreapi/qsgrenderer.cpp
new file mode 100644
index 0000000000..04c0817f8f
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgrenderer.cpp
@@ -0,0 +1,544 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrenderer_p.h"
+#include "qsgnode.h"
+#include "qsgmaterial.h"
+#include "qsgnodeupdater_p.h"
+
+#include "private/qsgadaptationlayer_p.h"
+
+#include <QGLShaderProgram>
+#include <qglframebufferobject.h>
+#include <QtGui/qapplication.h>
+
+#include <qdatetime.h>
+
+QT_BEGIN_NAMESPACE
+
+//#define RENDERER_DEBUG
+//#define QT_GL_NO_SCISSOR_TEST
+
+// #define QSG_RENDERER_TIMING
+#ifdef QSG_RENDERER_TIMING
+static QTime frameTimer;
+static int preprocessTime;
+static int updatePassTime;
+static int frameNumber = 0;
+#endif
+
+void Bindable::clear(QSGRenderer::ClearMode mode) const
+{
+ GLuint bits = 0;
+ if (mode & QSGRenderer::ClearColorBuffer) bits |= GL_COLOR_BUFFER_BIT;
+ if (mode & QSGRenderer::ClearDepthBuffer) bits |= GL_DEPTH_BUFFER_BIT;
+ if (mode & QSGRenderer::ClearStencilBuffer) bits |= GL_STENCIL_BUFFER_BIT;
+ glClear(bits);
+}
+
+// Reactivate the color buffer after switching to the stencil.
+void Bindable::reactivate() const
+{
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+}
+
+BindableFbo::BindableFbo(QGLFramebufferObject *fbo) : m_fbo(fbo)
+{
+}
+
+
+void BindableFbo::bind() const
+{
+ m_fbo->bind();
+}
+
+/*!
+ \class QSGRenderer
+ \brief The renderer class is the abstract baseclass use for rendering the
+ QML scene graph.
+
+ The renderer is not tied to any particular surface. It expects a context to
+ be current and will render into that surface according to how the device rect,
+ viewport rect and projection transformation are set up.
+
+ Rendering is a sequence of steps initiated by calling renderScene(). This will
+ effectively draw the scene graph starting at the root node. The QSGNode::preprocess()
+ function will be called for all the nodes in the graph, followed by an update
+ pass which updates all matrices, opacity, clip states and similar in the graph.
+ Because the update pass is called after preprocess, it is safe to modify the graph
+ during preprocess. To run a custom update pass over the graph, install a custom
+ QSGNodeUpdater using setNodeUpdater(). Once all the graphs dirty states are updated,
+ the virtual render() function is called.
+
+ The render() function is implemented by QSGRenderer subclasses to render the graph
+ in the most optimal way for a given hardware.
+
+ The renderer can make use of stencil, depth and color buffers in addition to the
+ scissor rect.
+
+ \internal
+ */
+
+
+QSGRenderer::QSGRenderer(QSGContext *context)
+ : QObject()
+ , m_clear_color(Qt::transparent)
+ , m_clear_mode(ClearColorBuffer | ClearDepthBuffer)
+ , m_render_opacity(1)
+ , m_context(context)
+ , m_root_node(0)
+ , m_node_updater(0)
+ , m_changed_emitted(false)
+ , m_mirrored(false)
+ , m_is_rendering(false)
+ , m_bindable(0)
+{
+ initializeGLFunctions();
+}
+
+
+QSGRenderer::~QSGRenderer()
+{
+ setRootNode(0);
+ delete m_node_updater;
+}
+
+/*!
+ Returns the scene graph context for this renderer.
+
+ \internal
+ */
+
+QSGContext *QSGRenderer::context()
+{
+ return m_context;
+}
+
+
+
+
+/*!
+ Returns the node updater that this renderer uses to update states in the
+ scene graph.
+
+ If no updater is specified a default one is constructed.
+ */
+
+QSGNodeUpdater *QSGRenderer::nodeUpdater() const
+{
+ if (!m_node_updater)
+ const_cast<QSGRenderer *>(this)->m_node_updater = new QSGNodeUpdater();
+ return m_node_updater;
+}
+
+
+/*!
+ Sets the node updater that this renderer uses to update states in the
+ scene graph.
+
+ This will delete and override any existing node updater
+ */
+void QSGRenderer::setNodeUpdater(QSGNodeUpdater *updater)
+{
+ if (m_node_updater)
+ delete m_node_updater;
+ m_node_updater = updater;
+}
+
+
+void QSGRenderer::setRootNode(QSGRootNode *node)
+{
+ if (m_root_node == node)
+ return;
+ if (m_root_node) {
+ m_root_node->m_renderers.removeOne(this);
+ nodeChanged(m_root_node, QSGNode::DirtyNodeRemoved);
+ }
+ m_root_node = node;
+ if (m_root_node) {
+ Q_ASSERT(!m_root_node->m_renderers.contains(this));
+ m_root_node->m_renderers << this;
+ nodeChanged(m_root_node, QSGNode::DirtyNodeAdded);
+ }
+}
+
+
+void QSGRenderer::renderScene()
+{
+ class B : public Bindable
+ {
+ public:
+ B() : m_ctx(const_cast<QGLContext *>(QGLContext::currentContext())) { }
+ void bind() const { QGLFramebufferObject::bindDefault(); }
+ private:
+ QGLContext *m_ctx;
+ } b;
+ renderScene(b);
+}
+
+void QSGRenderer::renderScene(const Bindable &bindable)
+{
+ if (!m_root_node)
+ return;
+
+ m_is_rendering = true;
+#ifdef QSG_RENDERER_TIMING
+ frameTimer.start();
+#endif
+
+ m_bindable = &bindable;
+ preprocess();
+
+ bindable.bind();
+#ifdef QSG_RENDERER_TIMING
+ int bindTime = frameTimer.elapsed();
+#endif
+
+ render();
+#ifdef QSG_RENDERER_TIMING
+ int renderTime = frameTimer.elapsed();
+#endif
+
+ glDisable(GL_SCISSOR_TEST);
+ m_is_rendering = false;
+ m_changed_emitted = false;
+ m_bindable = 0;
+
+#ifdef QSG_RENDERER_TIMING
+ printf(" - Breakdown of frametime: preprocess=%d, updates=%d, binding=%d, render=%d, total=%d\n",
+ preprocessTime,
+ updatePassTime - preprocessTime,
+ bindTime - updatePassTime,
+ renderTime - bindTime,
+ renderTime);
+#endif
+}
+
+void QSGRenderer::setProjectMatrixToDeviceRect()
+{
+ setProjectMatrixToRect(m_device_rect);
+}
+
+void QSGRenderer::setProjectMatrixToRect(const QRectF &rect)
+{
+ QMatrix4x4 matrix;
+ matrix.ortho(rect.x(),
+ rect.x() + rect.width(),
+ rect.y() + rect.height(),
+ rect.y(),
+ qreal(0.01),
+ -1);
+ setProjectMatrix(matrix);
+}
+
+void QSGRenderer::setProjectMatrix(const QMatrix4x4 &matrix)
+{
+ m_projection_matrix = matrix;
+ // Mirrored relative to the usual Qt coordinate system with origin in the top left corner.
+ m_mirrored = matrix(0, 0) * matrix(1, 1) - matrix(0, 1) * matrix(1, 0) > 0;
+}
+
+void QSGRenderer::setClearColor(const QColor &color)
+{
+ m_clear_color = color;
+}
+
+void QSGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags)
+{
+ Q_UNUSED(node);
+ Q_UNUSED(flags);
+
+ if (flags & QSGNode::DirtyNodeAdded)
+ addNodesToPreprocess(node);
+ if (flags & QSGNode::DirtyNodeRemoved)
+ removeNodesToPreprocess(node);
+
+ if (!m_changed_emitted && !m_is_rendering) {
+ // Premature overoptimization to avoid excessive signal emissions
+ m_changed_emitted = true;
+ emit sceneGraphChanged();
+ }
+}
+
+void QSGRenderer::materialChanged(QSGGeometryNode *, QSGMaterial *, QSGMaterial *)
+{
+}
+
+void QSGRenderer::preprocess()
+{
+ Q_ASSERT(m_root_node);
+
+ // We need to take a copy here, in case any of the preprocess calls deletes a node that
+ // is in the preprocess list and thus, changes the m_nodes_to_preprocess behind our backs
+ // For the default case, when this does not happen, the cost is neglishible.
+ QSet<QSGNode *> items = m_nodes_to_preprocess;
+
+ for (QSet<QSGNode *>::const_iterator it = items.constBegin();
+ it != items.constEnd(); ++it) {
+ QSGNode *n = *it;
+ if (!nodeUpdater()->isNodeBlocked(n, m_root_node)) {
+ n->preprocess();
+ }
+ }
+
+#ifdef QSG_RENDERER_TIMING
+ preprocessTime = frameTimer.elapsed();
+#endif
+
+ nodeUpdater()->setToplevelOpacity(context()->renderAlpha());
+ nodeUpdater()->updateStates(m_root_node);
+
+#ifdef QSG_RENDERER_TIMING
+ updatePassTime = frameTimer.elapsed();
+#endif
+
+}
+
+void QSGRenderer::addNodesToPreprocess(QSGNode *node)
+{
+ for (int i = 0; i < node->childCount(); ++i)
+ addNodesToPreprocess(node->childAtIndex(i));
+ if (node->flags() & QSGNode::UsePreprocess)
+ m_nodes_to_preprocess.insert(node);
+}
+
+void QSGRenderer::removeNodesToPreprocess(QSGNode *node)
+{
+ for (int i = 0; i < node->childCount(); ++i)
+ removeNodesToPreprocess(node->childAtIndex(i));
+ if (node->flags() & QSGNode::UsePreprocess)
+ m_nodes_to_preprocess.remove(node);
+}
+
+
+/*!
+ Convenience function to set up the stencil buffer for clipping based on \a clip.
+
+ If the clip is a pixel aligned rectangle, this function will use glScissor instead
+ of stencil.
+ */
+
+QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip)
+{
+ if (!clip) {
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ return NoClip;
+ }
+
+ bool stencilEnabled = false;
+ bool scissorEnabled = false;
+
+ glDisable(GL_SCISSOR_TEST);
+
+ int clipDepth = 0;
+ QRect clipRect;
+ while (clip) {
+ QMatrix4x4 matrix = m_projectionMatrix.top();
+ if (clip->matrix())
+ matrix *= *clip->matrix();
+
+ const QMatrix4x4 &m = matrix;
+
+ // TODO: Check for multisampling and pixel grid alignment.
+ bool canUseScissor = clip->isRectangular()
+ && qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(0, 2))
+ && qFuzzyIsNull(m(1, 0)) && qFuzzyIsNull(m(1, 2));
+
+ if (canUseScissor) {
+ QRectF bbox = clip->clipRect();
+ qreal invW = 1 / m(3, 3);
+ qreal fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW;
+ qreal fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW;
+ qreal fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW;
+ qreal fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW;
+
+ GLint ix1 = qRound((fx1 + 1) * m_device_rect.width() * qreal(0.5));
+ GLint iy1 = qRound((fy1 + 1) * m_device_rect.height() * qreal(0.5));
+ GLint ix2 = qRound((fx2 + 1) * m_device_rect.width() * qreal(0.5));
+ GLint iy2 = qRound((fy2 + 1) * m_device_rect.height() * qreal(0.5));
+
+ if (!scissorEnabled) {
+ clipRect = QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
+ glEnable(GL_SCISSOR_TEST);
+ scissorEnabled = true;
+ } else {
+ clipRect &= QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
+ }
+
+ clipRect = clipRect.normalized();
+ glScissor(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
+ } else {
+ if (!stencilEnabled) {
+ if (!m_clip_program.isLinked()) {
+ m_clip_program.addShaderFromSourceCode(QGLShader::Vertex,
+ "attribute highp vec4 vCoord; \n"
+ "uniform highp mat4 matrix; \n"
+ "void main() { \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}");
+ m_clip_program.addShaderFromSourceCode(QGLShader::Fragment,
+ "void main() { \n"
+ " gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); \n" // Trolltech green ftw!
+ "}");
+ m_clip_program.bindAttributeLocation("vCoord", 0);
+ m_clip_program.link();
+ m_clip_matrix_id = m_clip_program.uniformLocation("matrix");
+ }
+
+ glStencilMask(0xff); // write mask
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glEnable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ glDepthMask(GL_FALSE);
+
+ m_clip_program.bind();
+ m_clip_program.enableAttributeArray(0);
+
+ stencilEnabled = true;
+ }
+
+ glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask
+ glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // stencil fail, z fail, z pass
+
+ const QSGGeometry *geometry = clip->geometry();
+ Q_ASSERT(geometry->attributeCount() > 0);
+ const QSGGeometry::Attribute *a = geometry->attributes();
+
+ glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, geometry->stride(), geometry->vertexData());
+
+ m_clip_program.setUniformValue(m_clip_matrix_id, m);
+ draw(clip);
+
+ ++clipDepth;
+ }
+
+ clip = clip->clipList();
+ }
+
+ if (stencilEnabled) {
+ m_clip_program.disableAttributeArray(0);
+ glEnable(GL_DEPTH_TEST);
+ glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // stencil fail, z fail, z pass
+ glStencilMask(0); // write mask
+ bindable()->reactivate();
+ //glDepthMask(GL_TRUE); // must be reset correctly by caller.
+ } else {
+ glDisable(GL_STENCIL_TEST);
+ }
+
+ if (!scissorEnabled)
+ glDisable(GL_SCISSOR_TEST);
+
+ return stencilEnabled ? StencilClip : ScissorClip;
+}
+
+
+/*!
+ Issues the GL draw call for \a geometryNode.
+
+ The function assumes that attributes have been bound and set up prior
+ to making this call.
+
+ \internal
+ */
+
+void QSGRenderer::draw(const QSGBasicGeometryNode *node)
+{
+ const QSGGeometry *g = node->geometry();
+ if (g->indexCount()) {
+ glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
+ } else {
+ glDrawArrays(g->drawingMode(), 0, g->vertexCount());
+ }
+}
+
+
+static inline int size_of_type(GLenum type)
+{
+ static int sizes[] = {
+ sizeof(char),
+ sizeof(unsigned char),
+ sizeof(short),
+ sizeof(unsigned short),
+ sizeof(int),
+ sizeof(unsigned int),
+ sizeof(float),
+ 2,
+ 3,
+ 4,
+ sizeof(double)
+ };
+ return sizes[type - GL_BYTE];
+}
+
+/*!
+ Convenience function to set up and bind the vertex data in \a g to the
+ required attribute positions defined in \a material.
+
+ \internal
+ */
+
+void QSGRenderer::bindGeometry(QSGMaterialShader *material, const QSGGeometry *g)
+{
+ char const *const *attrNames = material->attributeNames();
+ int offset = 0;
+ for (int j = 0; attrNames[j]; ++j) {
+ if (!*attrNames[j])
+ continue;
+ Q_ASSERT_X(j < g->attributeCount(), "QSGRenderer::bindGeometry()", "Geometry lacks attribute required by material");
+ const QSGGeometry::Attribute &a = g->attributes()[j];
+ Q_ASSERT_X(j == a.position, "QSGRenderer::bindGeometry()", "Geometry does not have continuous attribute positions");
+#if defined(QT_OPENGL_ES_2)
+ GLboolean normalize = a.type != GL_FLOAT;
+#else
+ GLboolean normalize = a.type != GL_FLOAT && a.type != GL_DOUBLE;
+#endif
+ glVertexAttribPointer(a.position, a.tupleSize, a.type, normalize, g->stride(), (char *) g->vertexData() + offset);
+ offset += a.tupleSize * size_of_type(a.type);
+ }
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/coreapi/qsgrenderer_p.h b/src/declarative/scenegraph/coreapi/qsgrenderer_p.h
new file mode 100644
index 0000000000..fcf966d819
--- /dev/null
+++ b/src/declarative/scenegraph/coreapi/qsgrenderer_p.h
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include <qset.h>
+#include <qhash.h>
+
+#include "qsgmatrix4x4stack.h"
+
+#include <qglfunctions.h>
+#include <qglshaderprogram.h>
+
+#include "qsgnode.h"
+#include "qsgmaterial.h"
+#include "qsgtexture.h"
+
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMaterialShader;
+struct QSGMaterialType;
+class QGLFramebufferObject;
+class TextureReference;
+class Bindable;
+class QSGNodeUpdater;
+
+
+class Q_DECLARATIVE_EXPORT QSGRenderer : public QObject, public QGLFunctions
+{
+ Q_OBJECT
+public:
+ enum ClipType
+ {
+ NoClip,
+ ScissorClip,
+ StencilClip
+ };
+
+ enum ClearModeBit
+ {
+ ClearColorBuffer = 0x0001,
+ ClearDepthBuffer = 0x0002,
+ ClearStencilBuffer = 0x0004
+ };
+ Q_DECLARE_FLAGS(ClearMode, ClearModeBit)
+
+ QSGRenderer(QSGContext *context);
+ virtual ~QSGRenderer();
+
+ void setRootNode(QSGRootNode *node);
+ QSGRootNode *rootNode() const { return m_root_node; }
+
+ void setDeviceRect(const QRect &rect) { m_device_rect = rect; }
+ inline void setDeviceRect(const QSize &size) { setDeviceRect(QRect(QPoint(), size)); }
+ QRect deviceRect() const { return m_device_rect; }
+
+ void setViewportRect(const QRect &rect) { m_viewport_rect = rect; }
+ inline void setViewportRect(const QSize &size) { setViewportRect(QRect(QPoint(), size)); }
+ QRect viewportRect() const { return m_viewport_rect; }
+
+ QSGMatrix4x4Stack &projectionMatrix() { return m_projectionMatrix; }
+ QSGMatrix4x4Stack &modelViewMatrix() { return m_modelViewMatrix; }
+ QMatrix4x4 combinedMatrix() const { return m_projectionMatrix.top() * m_modelViewMatrix.top(); }
+
+ void setProjectMatrixToDeviceRect();
+ void setProjectMatrixToRect(const QRectF &rect);
+ void setProjectMatrix(const QMatrix4x4 &matrix);
+ QMatrix4x4 projectMatrix() const { return m_projection_matrix; }
+ bool isMirrored() const { return m_mirrored; }
+
+ qreal renderOpacity() const { return m_render_opacity; }
+
+ void setClearColor(const QColor &color);
+ QColor clearColor() const { return m_clear_color; }
+
+ const QGLContext *glContext() const { Q_ASSERT(m_context); return m_context->glContext(); }
+
+ QSGContext *context();
+
+ void renderScene();
+ void renderScene(const Bindable &bindable);
+ virtual void nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags);
+ virtual void materialChanged(QSGGeometryNode *node, QSGMaterial *from, QSGMaterial *to);
+
+ QSGNodeUpdater *nodeUpdater() const;
+ void setNodeUpdater(QSGNodeUpdater *updater);
+
+ inline QSGMaterialShader::RenderState state(QSGMaterialShader::RenderState::DirtyStates dirty) const;
+
+ void setClearMode(ClearMode mode) { m_clear_mode = mode; }
+ ClearMode clearMode() const { return m_clear_mode; }
+
+signals:
+ void sceneGraphChanged(); // Add, remove, ChangeFlags changes...
+
+protected:
+ void draw(const QSGBasicGeometryNode *geometry);
+ void bindGeometry(QSGMaterialShader *material, const QSGGeometry *g);
+
+ virtual void render() = 0;
+ QSGRenderer::ClipType updateStencilClip(const QSGClipNode *clip);
+
+ const Bindable *bindable() const { return m_bindable; }
+
+ virtual void preprocess();
+
+ void addNodesToPreprocess(QSGNode *node);
+ void removeNodesToPreprocess(QSGNode *node);
+
+
+ QColor m_clear_color;
+ ClearMode m_clear_mode;
+ QSGMatrix4x4Stack m_projectionMatrix;
+ QSGMatrix4x4Stack m_modelViewMatrix;
+ qreal m_render_opacity;
+
+ QSGContext *m_context;
+
+private:
+ QSGRootNode *m_root_node;
+ QSGNodeUpdater *m_node_updater;
+
+ QRect m_device_rect;
+ QRect m_viewport_rect;
+
+ QSet<QSGNode *> m_nodes_to_preprocess;
+
+ QMatrix4x4 m_projection_matrix;
+ QGLShaderProgram m_clip_program;
+ int m_clip_matrix_id;
+
+ bool m_changed_emitted;
+ bool m_mirrored;
+ bool m_is_rendering;
+
+ const Bindable *m_bindable;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderer::ClearMode)
+
+class Q_DECLARATIVE_EXPORT Bindable
+{
+public:
+ virtual ~Bindable() { }
+ virtual void bind() const = 0;
+ virtual void clear(QSGRenderer::ClearMode mode) const;
+ virtual void reactivate() const;
+};
+
+class BindableFbo : public Bindable
+{
+public:
+ BindableFbo(QGLFramebufferObject *fbo);
+ virtual void bind() const;
+private:
+ QGLFramebufferObject *m_fbo;
+};
+
+
+
+QSGMaterialShader::RenderState QSGRenderer::state(QSGMaterialShader::RenderState::DirtyStates dirty) const
+{
+ QSGMaterialShader::RenderState s;
+ s.m_dirty = dirty;
+ s.m_data = this;
+ return s;
+}
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // RENDERER_H
diff --git a/src/declarative/scenegraph/qsgadaptationlayer.cpp b/src/declarative/scenegraph/qsgadaptationlayer.cpp
new file mode 100644
index 0000000000..81fac6a1a8
--- /dev/null
+++ b/src/declarative/scenegraph/qsgadaptationlayer.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgadaptationlayer_p.h"
diff --git a/src/declarative/scenegraph/qsgadaptationlayer_p.h b/src/declarative/scenegraph/qsgadaptationlayer_p.h
new file mode 100644
index 0000000000..1e7c794ea9
--- /dev/null
+++ b/src/declarative/scenegraph/qsgadaptationlayer_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ADAPTATIONINTERFACES_H
+#define ADAPTATIONINTERFACES_H
+
+#include "qsgnode.h"
+#include "qsgtexture.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qcolor.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtGui/qglyphs.h>
+#include <QtCore/qurl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGNode;
+class QImage;
+class TextureReference;
+
+// TODO: Rename from XInterface to AbstractX.
+class Q_DECLARATIVE_EXPORT QSGRectangleNode : public QSGGeometryNode
+{
+public:
+ virtual void setRect(const QRectF &rect) = 0;
+ virtual void setColor(const QColor &color) = 0;
+ virtual void setPenColor(const QColor &color) = 0;
+ virtual void setPenWidth(qreal width) = 0;
+ virtual void setGradientStops(const QGradientStops &stops) = 0;
+ virtual void setRadius(qreal radius) = 0;
+
+ virtual void update() = 0;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGImageNode : public QSGGeometryNode
+{
+public:
+ virtual void setTargetRect(const QRectF &rect) = 0;
+ virtual void setSourceRect(const QRectF &rect) = 0;
+ virtual void setTexture(QSGTexture *texture) = 0;
+
+ virtual void setMipmapFiltering(QSGTexture::Filtering filtering) = 0;
+ virtual void setFiltering(QSGTexture::Filtering filtering) = 0;
+ virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) = 0;
+ virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode) = 0;
+
+ virtual void update() = 0;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGGlyphNode : public QSGGeometryNode
+{
+public:
+ enum AntialiasingMode
+ {
+ GrayAntialiasing,
+ SubPixelAntialiasing
+ };
+
+ virtual void setGlyphs(const QPointF &position, const QGlyphs &glyphs) = 0;
+ virtual void setColor(const QColor &color) = 0;
+ virtual QPointF baseLine() const = 0;
+
+ virtual QRectF boundingRect() const { return m_bounding_rect; }
+ virtual void setBoundingRect(const QRectF &bounds) { m_bounding_rect = bounds; }
+
+ virtual void setPreferredAntialiasingMode(AntialiasingMode) = 0;
+
+protected:
+ QRectF m_bounding_rect;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/qsgcontext.cpp b/src/declarative/scenegraph/qsgcontext.cpp
new file mode 100644
index 0000000000..2a43d03028
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontext.cpp
@@ -0,0 +1,428 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qsgcontext_p.h>
+#include <private/qsgrenderer_p.h>
+#include "qsgnode.h"
+
+#include <private/qsgdefaultrenderer_p.h>
+
+#include <private/qsgdefaultrectanglenode_p.h>
+#include <private/qsgdefaultimagenode_p.h>
+#include <private/qsgdefaultglyphnode_p.h>
+#include <private/qsgdistancefieldglyphnode_p.h>
+#include <private/qsgdistancefieldglyphcache_p.h>
+
+#include <private/qsgtexture_p.h>
+#include <qsgengine.h>
+
+#include <QApplication>
+#include <QGLContext>
+
+#include <private/qobject_p.h>
+#include <qmutex.h>
+
+DEFINE_BOOL_CONFIG_OPTION(qmlFlashMode, QML_FLASH_MODE)
+DEFINE_BOOL_CONFIG_OPTION(qmlTranslucentMode, QML_TRANSLUCENT_MODE)
+
+/*!
+ Comments about this class from Gunnar:
+
+ The QSGContext class is right now two things.. The first is the
+ adaptation layer and central storage ground for all the things
+ in the scene graph, like textures and materials. This part really
+ belongs inside the scene graph coreapi.
+
+ The other part is the QML adaptation classes, like how to implement
+ rectangle nodes. This is not part of the scene graph core API, but
+ more part of the QML adaptation of scene graph.
+
+ If we ever move the scene graph core API into its own thing, this class
+ needs to be split in two. Right now its one because we're lazy when it comes
+ to defining plugin interfaces..
+
+ */
+
+
+QT_BEGIN_NAMESPACE
+
+class QSGContextPrivate : public QObjectPrivate
+{
+public:
+ QSGContextPrivate()
+ : rootNode(0)
+ , renderer(0)
+ , gl(0)
+ , flashMode(qmlFlashMode())
+ {
+ renderAlpha = qmlTranslucentMode() ? 0.5 : 1;
+ }
+
+ ~QSGContextPrivate()
+ {
+ }
+
+ QSGRootNode *rootNode;
+ QSGRenderer *renderer;
+
+ QGLContext *gl;
+
+ QSGEngine engine;
+
+ QHash<QSGMaterialType *, QSGMaterialShader *> materials;
+
+ QMutex textureMutex;
+ QList<QSGTexture *> texturesToClean;
+
+ bool flashMode;
+ float renderAlpha;
+};
+
+
+/*!
+ \class QSGContext
+
+ \brief The QSGContext holds the scene graph entry points for one QML engine.
+
+ The context is not ready for use until it has a QGLContext. Once that happens,
+ the scene graph population can start.
+
+ \internal
+ */
+
+QSGContext::QSGContext(QObject *parent) :
+ QObject(*(new QSGContextPrivate), parent)
+{
+ Q_D(QSGContext);
+ d->engine.setContext(this);
+}
+
+
+QSGContext::~QSGContext()
+{
+ Q_D(QSGContext);
+ delete d->renderer;
+ delete d->rootNode;
+ cleanupTextures();
+ qDeleteAll(d->materials.values());
+}
+
+/*!
+ Returns the scene graph engine for this context.
+
+ The main purpose of the QSGEngine is to serve as a public API
+ to the QSGContext.
+
+ */
+QSGEngine *QSGContext::engine() const
+{
+ return const_cast<QSGEngine *>(&d_func()->engine);
+}
+
+/*!
+ Schedules the texture to be cleaned up on the rendering thread
+ at a later time.
+
+ The texture can be considered as deleted after this function has
+ been called.
+ */
+void QSGContext::schdelueTextureForCleanup(QSGTexture *texture)
+{
+ Q_D(QSGContext);
+ d->textureMutex.lock();
+ Q_ASSERT(!d->texturesToClean.contains(texture));
+ d->texturesToClean << texture;
+ d->textureMutex.unlock();
+}
+
+
+
+/*!
+ Deletes all textures that have been scheduled for cleanup
+ */
+void QSGContext::cleanupTextures()
+{
+ Q_D(QSGContext);
+ d->textureMutex.lock();
+ qDeleteAll(d->texturesToClean);
+ d->texturesToClean.clear();
+ d->textureMutex.unlock();
+}
+
+/*!
+ Returns the renderer. The renderer instance is created through the adaptation layer.
+ */
+QSGRenderer *QSGContext::renderer() const
+{
+ Q_D(const QSGContext);
+ return d->renderer;
+}
+
+
+/*!
+ Returns the root node. The root node instance is only created once the scene graph
+ context becomes ready.
+ */
+QSGRootNode *QSGContext::rootNode() const
+{
+ Q_D(const QSGContext);
+ return d->rootNode;
+}
+
+
+QGLContext *QSGContext::glContext() const
+{
+ Q_D(const QSGContext);
+ return d->gl;
+}
+
+/*!
+ Initializes the scene graph context with the GL context \a context. This also
+ emits the ready() signal so that the QML graph can start building scene graph nodes.
+ */
+void QSGContext::initialize(QGLContext *context)
+{
+ Q_D(QSGContext);
+
+ Q_ASSERT(!d->gl);
+
+ d->gl = context;
+
+ d->renderer = createRenderer();
+ d->renderer->setClearColor(Qt::white);
+
+ d->rootNode = new QSGRootNode();
+ d->renderer->setRootNode(d->rootNode);
+
+ emit ready();
+}
+
+
+/*!
+ Returns if the scene graph context is ready or not, meaning that it has a valid
+ GL context.
+ */
+bool QSGContext::isReady() const
+{
+ Q_D(const QSGContext);
+ return d->gl;
+}
+
+
+void QSGContext::renderNextFrame()
+{
+ Q_D(QSGContext);
+
+ emit d->engine.beforeRendering();
+
+ cleanupTextures();
+ d->renderer->renderScene();
+
+ emit d->engine.afterRendering();
+
+}
+
+/*!
+ Factory function for scene graph backends of the Rectangle element.
+ */
+QSGRectangleNode *QSGContext::createRectangleNode()
+{
+ return new QSGDefaultRectangleNode(this);
+}
+
+/*!
+ Factory function for scene graph backends of the Image element.
+ */
+QSGImageNode *QSGContext::createImageNode()
+{
+ return new QSGDefaultImageNode;
+}
+
+/*!
+ Factory function for scene graph backends of the Text elements;
+ */
+QSGGlyphNode *QSGContext::createGlyphNode()
+{
+ if (QSGDistanceFieldGlyphCache::distanceFieldEnabled()) {
+ QSGGlyphNode *node = new QSGDistanceFieldGlyphNode;
+ if (qApp->arguments().contains(QLatin1String("--subpixel-antialiasing")))
+ node->setPreferredAntialiasingMode(QSGGlyphNode::SubPixelAntialiasing);
+ return node;
+ } else {
+ return new QSGDefaultGlyphNode;
+ }
+}
+
+/*!
+ Factory function for the scene graph renderers.
+
+ The renderers are used for the toplevel renderer and once for every
+ QSGShaderEffectSource used in the QML scene.
+ */
+QSGRenderer *QSGContext::createRenderer()
+{
+ QMLRenderer *renderer = new QMLRenderer(this);
+ if (qApp->arguments().contains(QLatin1String("--opaque-front-to-back"))) {
+ printf("QSGContext: Sorting opaque nodes front to back...\n");
+ renderer->setSortFrontToBackEnabled(true);
+ }
+ return renderer;
+}
+
+
+
+/*!
+ Return true if the image provider supports direct decoding of images,
+ straight into textures without going through a QImage first.
+
+ If the implementation returns true from this function, the decodeImageToTexture() function
+ will be called to read data from a QIODevice, rather than QML decoding
+ the image using QImageReader and passing the result to setImage().
+
+ \warning This function will be called from outside the GUI and rendering threads
+ and must not make use of OpenGL.
+ */
+
+bool QSGContext::canDecodeImageToTexture() const
+{
+ return true;
+}
+
+
+
+/*!
+ Decode the data in \a dev directly to a texture provider of \a requestSize size.
+ The size of the decoded data should be written to \a impsize.
+
+ If the implementation fails to decode the image data, it should return 0. The
+ image data will then be decoded normally.
+
+ \warning This function will be called from outside the GUI and renderer threads
+ and must not make use of GL calls.
+ */
+
+QSGTexture *QSGContext::decodeImageToTexture(QIODevice *dev,
+ QSize *size,
+ const QSize &requestSize)
+{
+ Q_UNUSED(dev);
+ Q_UNUSED(size);
+ Q_UNUSED(requestSize);
+ return 0;
+}
+
+
+/*!
+ Factory function for texture objects.
+
+ If \a image is a valid image, the QSGTexture::setImage function
+ will be called with \a image as argument.
+ */
+QSGTexture *QSGContext::createTexture(const QImage &image) const
+{
+ QSGPlainTexture *t = new QSGPlainTexture();
+ if (!image.isNull())
+ t->setImage(image);
+ return t;
+}
+
+
+/*!
+ Returns a material shader for the given material.
+ */
+QSGMaterialShader *QSGContext::prepareMaterial(QSGMaterial *material)
+{
+ Q_D(QSGContext);
+ QSGMaterialType *type = material->type();
+ QSGMaterialShader *shader = d->materials.value(type);
+ if (shader)
+ return shader;
+
+ shader = material->createShader();
+ d->materials[type] = shader;
+ return shader;
+}
+
+/*!
+ Sets weither the scene graph should render with flashing update rectangles or not
+ */
+void QSGContext::setFlashModeEnabled(bool enabled)
+{
+ d_func()->flashMode = enabled;
+}
+
+
+/*!
+ Returns true if the scene graph should be rendered with flashing update rectangles
+ */
+bool QSGContext::isFlashModeEnabled() const
+{
+ return d_func()->flashMode;
+}
+
+
+/*!
+ Sets the toplevel opacity for rendering. This value will be multiplied into all
+ drawing calls where possible.
+
+ The default value is 1. Any other value will cause artifacts and is primarily
+ useful for debugging.
+ */
+void QSGContext::setRenderAlpha(qreal renderAlpha)
+{
+ d_func()->renderAlpha = renderAlpha;
+}
+
+
+/*!
+ Returns the toplevel opacity used for rendering.
+
+ The default value is 1.
+
+ \sa setRenderAlpha()
+ */
+qreal QSGContext::renderAlpha() const
+{
+ return d_func()->renderAlpha;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgcontext_p.h b/src/declarative/scenegraph/qsgcontext_p.h
new file mode 100644
index 0000000000..848dd17ad0
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontext_p.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCONTEXT_H
+#define QSGCONTEXT_H
+
+#include <QObject>
+#include <qabstractanimation.h>
+
+#include "qsgnode.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGContextPrivate;
+class QSGRectangleNode;
+class QSGImageNode;
+class QSGGlyphNode;
+class QSGRenderer;
+
+class QSGTexture;
+class QSGMaterial;
+class QSGMaterialShader;
+class QSGEngine;
+
+class QGLContext;
+
+class Q_DECLARATIVE_EXPORT QSGContext : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGContext)
+
+public:
+ explicit QSGContext(QObject *parent = 0);
+ ~QSGContext();
+
+ virtual void initialize(QGLContext *context);
+
+ QSGRenderer *renderer() const;
+
+ void setRootNode(QSGRootNode *node);
+ QSGRootNode *rootNode() const;
+
+ QSGEngine *engine() const;
+ QGLContext *glContext() const;
+
+ bool isReady() const;
+
+ QSGMaterialShader *prepareMaterial(QSGMaterial *material);
+
+ virtual void renderNextFrame();
+
+ virtual QSGRectangleNode *createRectangleNode();
+ virtual QSGImageNode *createImageNode();
+ virtual QSGGlyphNode *createGlyphNode();
+ virtual QSGRenderer *createRenderer();
+
+ virtual bool canDecodeImageToTexture() const;
+ virtual QSGTexture *decodeImageToTexture(QIODevice *dev,
+ QSize *size,
+ const QSize &requestSize);
+ virtual QSGTexture *createTexture(const QImage &image = QImage()) const;
+
+ static QSGContext *createDefaultContext();
+
+ void schdelueTextureForCleanup(QSGTexture *texture);
+ void cleanupTextures();
+
+ void setFlashModeEnabled(bool enabled);
+ bool isFlashModeEnabled() const;
+
+ void setRenderAlpha(qreal renderAlpha);
+ qreal renderAlpha() const;
+
+signals:
+ void ready();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGCONTEXT_H
diff --git a/src/declarative/scenegraph/qsgcontextplugin.cpp b/src/declarative/scenegraph/qsgcontextplugin.cpp
new file mode 100644
index 0000000000..287db68fa3
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontextplugin.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgcontextplugin_p.h"
+#include <private/qsgcontext_p.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/private/qfactoryloader_p.h>
+#include <QtCore/qlibraryinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGContextPlugin::QSGContextPlugin(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QSGContextPlugin::~QSGContextPlugin()
+{
+}
+
+#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QSGContextFactoryInterface_iid, QLatin1String("/scenegraph")))
+#endif
+
+/*!
+ \fn QSGContext *QSGContext::createDefaultContext()
+
+ Creates a default scene graph context for the current hardware.
+ This may load a device-specific plugin.
+*/
+QSGContext *QSGContext::createDefaultContext()
+{
+ const QStringList args = QApplication::arguments();
+ QString device;
+ for (int index = 0; index < args.count(); ++index) {
+ if (args.at(index).startsWith(QLatin1String("--device="))) {
+ device = args.at(index).mid(9);
+ break;
+ }
+ }
+ if (device.isEmpty())
+ device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE"));
+ if (device.isEmpty())
+ return new QSGContext();
+
+#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+ if (QSGContextFactoryInterface *factory
+ = qobject_cast<QSGContextFactoryInterface*>
+ (loader()->instance(device))) {
+ QSGContext *context = factory->create(device);
+ if (context)
+ return context;
+ }
+#ifndef QT_NO_DEBUG
+ qWarning("Could not create scene graph context for device '%s'"
+ " - check that plugins are installed correctly in %s",
+ qPrintable(device),
+ qPrintable(QLibraryInfo::location(QLibraryInfo::PluginsPath)));
+#endif
+#endif // QT_NO_LIBRARY || QT_NO_SETTINGS
+
+ return new QSGContext();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgcontextplugin_p.h b/src/declarative/scenegraph/qsgcontextplugin_p.h
new file mode 100644
index 0000000000..e36bc13a9b
--- /dev/null
+++ b/src/declarative/scenegraph/qsgcontextplugin_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGCONTEXTPLUGIN_H
+#define QSGCONTEXTPLUGIN_H
+
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGContext;
+
+struct Q_DECLARATIVE_EXPORT QSGContextFactoryInterface : public QFactoryInterface
+{
+ virtual QSGContext *create(const QString &key) const = 0;
+};
+
+#define QSGContextFactoryInterface_iid \
+ "com.trolltech.Qt.QSGContextFactoryInterface"
+Q_DECLARE_INTERFACE(QSGContextFactoryInterface, QSGContextFactoryInterface_iid)
+
+class Q_DECLARATIVE_EXPORT QSGContextPlugin : public QObject, public QSGContextFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QSGContextFactoryInterface:QFactoryInterface)
+public:
+ explicit QSGContextPlugin(QObject *parent = 0);
+ virtual ~QSGContextPlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QSGContext *create(const QString &key) const = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGCONTEXTPLUGIN_H
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode.cpp b/src/declarative/scenegraph/qsgdefaultglyphnode.cpp
new file mode 100644
index 0000000000..57482a9cf4
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultglyphnode_p.h"
+#include "qsgdefaultglyphnode_p_p.h"
+
+#include <qglshaderprogram.h>
+#include <private/qfont_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultGlyphNode::QSGDefaultGlyphNode()
+ : m_material(0)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
+{
+ m_geometry.setDrawingMode(GL_TRIANGLES);
+ setGeometry(&m_geometry);
+}
+
+QSGDefaultGlyphNode::~QSGDefaultGlyphNode()
+{
+ delete m_material;
+}
+
+void QSGDefaultGlyphNode::setColor(const QColor &color)
+{
+ m_color = color;
+ if (m_material != 0) {
+ m_material->setColor(color);
+ setMaterial(m_material); // Indicate the material state has changed
+ }
+}
+
+void QSGDefaultGlyphNode::setGlyphs(const QPointF &position, const QGlyphs &glyphs)
+{
+ if (m_material != 0)
+ delete m_material;
+
+ QRawFont font = glyphs.font();
+ m_material = new QSGTextMaskMaterial(font);
+ m_material->setColor(m_color);
+
+ QRectF boundingRect;
+ m_material->populate(position, glyphs.glyphIndexes(), glyphs.positions(), geometry(),
+ &boundingRect, &m_baseLine);
+
+ setMaterial(m_material);
+ setBoundingRect(boundingRect);
+
+ markDirty(DirtyGeometry);
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("glyphs");
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp b/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp
new file mode 100644
index 0000000000..00090be9ea
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -0,0 +1,313 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultglyphnode_p_p.h"
+
+#include <qglshaderprogram.h>
+
+#include <private/qtextureglyphcache_gl_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qglextensions_p.h>
+
+#include <private/qsgtexture_p.h>
+
+#include <private/qrawfont_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGTextMaskMaterialData : public QSGMaterialShader
+{
+public:
+ QSGTextMaskMaterialData();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+private:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ int m_matrix_id;
+ int m_color_id;
+ int m_textureScale_id;
+};
+
+const char *QSGTextMaskMaterialData::vertexShader() const {
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *QSGTextMaskMaterialData::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "void main() { \n"
+ " gl_FragColor = color * texture2D(texture, sampleCoord).a; \n"
+ "}";
+}
+
+char const *const *QSGTextMaskMaterialData::attributeNames() const
+{
+ static char const *const attr[] = { "vCoord", "tCoord", 0 };
+ return attr;
+}
+
+QSGTextMaskMaterialData::QSGTextMaskMaterialData()
+{
+}
+
+void QSGTextMaskMaterialData::initialize()
+{
+ m_matrix_id = m_program.uniformLocation("matrix");
+ m_color_id = m_program.uniformLocation("color");
+ m_textureScale_id = m_program.uniformLocation("textureScale");
+}
+
+void QSGTextMaskMaterialData::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGTextMaskMaterial *material = static_cast<QSGTextMaskMaterial *>(newEffect);
+ QSGTextMaskMaterial *oldMaterial = static_cast<QSGTextMaskMaterial *>(oldEffect);
+
+ if (oldMaterial == 0 || material->color() != oldMaterial->color() || state.isOpacityDirty()) {
+ QVector4D color(material->color().redF(), material->color().greenF(),
+ material->color().blueF(), material->color().alphaF());
+ color *= state.opacity();
+ m_program.setUniformValue(m_color_id, color);
+ }
+
+ bool updated = material->ensureUpToDate();
+ Q_ASSERT(material->texture());
+
+ Q_ASSERT(oldMaterial == 0 || oldMaterial->texture());
+ if (updated
+ || oldMaterial == 0
+ || oldMaterial->texture()->textureId() != material->texture()->textureId()) {
+ m_program.setUniformValue(m_textureScale_id, QVector2D(1.0 / material->cacheTextureWidth(),
+ 1.0 / material->cacheTextureHeight()));
+ glBindTexture(GL_TEXTURE_2D, material->texture()->textureId());
+
+ // Set the mag/min filters to be linear. We only need to do this when the texture
+ // has been recreated.
+ if (updated) {
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ }
+ }
+
+ if (state.isMatrixDirty())
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+}
+
+QSGTextMaskMaterial::QSGTextMaskMaterial(const QRawFont &font)
+ : m_texture(0), m_glyphCache(), m_font(font)
+{
+ init();
+}
+
+QSGTextMaskMaterial::~QSGTextMaskMaterial()
+{
+}
+
+void QSGTextMaskMaterial::init()
+{
+ Q_ASSERT(m_font.isValid());
+
+ QFontEngineGlyphCache::Type type = QFontEngineGlyphCache::Raster_A8;
+ setFlag(Blending, true);
+
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ Q_ASSERT(ctx != 0);
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ if (fontD->fontEngine != 0) {
+ m_glyphCache = fontD->fontEngine->glyphCache(ctx, type, QTransform());
+ if (!m_glyphCache || m_glyphCache->cacheType() != type) {
+ m_glyphCache = new QGLTextureGlyphCache(ctx, type, QTransform());
+ fontD->fontEngine->setGlyphCache(ctx, m_glyphCache.data());
+ }
+ }
+
+#if !defined(QT_OPENGL_ES_2)
+ bool success = qt_resolve_version_2_0_functions(ctx)
+ && qt_resolve_buffer_extensions(ctx);
+ Q_ASSERT(success);
+ Q_UNUSED(success);
+#endif
+}
+
+void QSGTextMaskMaterial::populate(const QPointF &p,
+ const QVector<quint32> &glyphIndexes,
+ const QVector<QPointF> &glyphPositions,
+ QSGGeometry *geometry,
+ QRectF *boundingRect,
+ QPointF *baseLine)
+{
+ Q_ASSERT(m_font.isValid());
+ QVector<QFixedPoint> fixedPointPositions;
+ for (int i=0; i<glyphPositions.size(); ++i)
+ fixedPointPositions.append(QFixedPoint::fromPointF(glyphPositions.at(i)));
+
+ QTextureGlyphCache *cache = glyphCache();
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(),
+ fixedPointPositions.data());
+ cache->fillInPendingGlyphs();
+
+ int margin = cache->glyphMargin();
+
+ Q_ASSERT(geometry->indexType() == GL_UNSIGNED_SHORT);
+ geometry->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6);
+ QVector4D *vp = (QVector4D *)geometry->vertexDataAsTexturedPoint2D();
+ Q_ASSERT(geometry->stride() == sizeof(QVector4D));
+ ushort *ip = geometry->indexDataAsUShort();
+
+ QPointF position(p.x(), p.y() - m_font.ascent());
+ bool supportsSubPixelPositions = fontD->fontEngine->supportsSubPixelPositions();
+ for (int i=0; i<glyphIndexes.size(); ++i) {
+ QFixed subPixelPosition;
+ if (supportsSubPixelPositions)
+ subPixelPosition = cache->subPixelPositionForX(QFixed::fromReal(glyphPositions.at(i).x()));
+
+ QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i), subPixelPosition);
+ const QTextureGlyphCache::Coord &c = cache->coords.value(glyph);
+
+ QPointF glyphPosition = glyphPositions.at(i) + position;
+ int x = qRound(glyphPosition.x()) + c.baseLineX - margin;
+ int y = qRound(glyphPosition.y()) - c.baseLineY - margin;
+
+ *boundingRect |= QRectF(x + margin, y + margin, c.w, c.h);
+
+ float cx1 = x;
+ float cx2 = x + c.w;
+ float cy1 = y;
+ float cy2 = y + c.h;
+
+ float tx1 = c.x;
+ float tx2 = (c.x + c.w);
+ float ty1 = c.y;
+ float ty2 = (c.y + c.h);
+
+ if (baseLine->isNull())
+ *baseLine = glyphPosition;
+
+ vp[4 * i + 0] = QVector4D(cx1, cy1, tx1, ty1);
+ vp[4 * i + 1] = QVector4D(cx2, cy1, tx2, ty1);
+ vp[4 * i + 2] = QVector4D(cx1, cy2, tx1, ty2);
+ vp[4 * i + 3] = QVector4D(cx2, cy2, tx2, ty2);
+
+ int o = i * 4;
+ ip[6 * i + 0] = o + 0;
+ ip[6 * i + 1] = o + 2;
+ ip[6 * i + 2] = o + 3;
+ ip[6 * i + 3] = o + 3;
+ ip[6 * i + 4] = o + 1;
+ ip[6 * i + 5] = o + 0;
+ }
+}
+
+QSGMaterialType *QSGTextMaskMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QGLTextureGlyphCache *QSGTextMaskMaterial::glyphCache() const
+{
+ return static_cast<QGLTextureGlyphCache*>(m_glyphCache.data());
+}
+
+QSGMaterialShader *QSGTextMaskMaterial::createShader() const
+{
+ return new QSGTextMaskMaterialData;
+}
+
+int QSGTextMaskMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGTextMaskMaterial *other = static_cast<const QSGTextMaskMaterial *>(o);
+ if (m_glyphCache != other->m_glyphCache)
+ return m_glyphCache - other->m_glyphCache;
+ QRgb c1 = m_color.rgba();
+ QRgb c2 = other->m_color.rgba();
+ return int(c2 < c1) - int(c1 < c2);
+}
+
+bool QSGTextMaskMaterial::ensureUpToDate()
+{
+ QSize glyphCacheSize(glyphCache()->width(), glyphCache()->height());
+ if (glyphCacheSize != m_size) {
+ if (m_texture)
+ delete m_texture;
+ m_texture = new QSGPlainTexture();
+ m_texture->setTextureId(glyphCache()->texture());
+ m_texture->setTextureSize(QSize(glyphCache()->width(), glyphCache()->height()));
+ m_texture->setOwnsTexture(false);
+
+ m_size = glyphCacheSize;
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int QSGTextMaskMaterial::cacheTextureWidth() const
+{
+ return glyphCache()->width();
+}
+
+int QSGTextMaskMaterial::cacheTextureHeight() const
+{
+ return glyphCache()->height();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode_p.h b/src/declarative/scenegraph/qsgdefaultglyphnode_p.h
new file mode 100644
index 0000000000..9e93bc4368
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEFAULT_GLYPHNODE_H
+#define DEFAULT_GLYPHNODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+#include <qsgnode.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QGlyphs;
+class QSGTextMaskMaterial;
+class QSGDefaultGlyphNode: public QSGGlyphNode
+{
+public:
+ QSGDefaultGlyphNode();
+ ~QSGDefaultGlyphNode();
+
+ virtual QPointF baseLine() const { return m_baseLine; }
+ virtual void setGlyphs(const QPointF &position, const QGlyphs &glyphs);
+ virtual void setColor(const QColor &color);
+
+ virtual void setPreferredAntialiasingMode(AntialiasingMode) { }
+
+private:
+ QGlyphs m_glyphs;
+ QPointF m_position;
+ QColor m_color;
+
+ QPointF m_baseLine;
+ QSGTextMaskMaterial *m_material;
+
+ QSGGeometry m_geometry;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // DEFAULT_GLYPHNODE_H
diff --git a/src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h b/src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h
new file mode 100644
index 0000000000..b5f0d70020
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultglyphnode_p_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTMASKMATERIAL_H
+#define TEXTMASKMATERIAL_H
+
+#include <qsgmaterial.h>
+#include <qsgtexture.h>
+#include <qsggeometry.h>
+#include <qshareddata.h>
+#include <private/qsgtexture_p.h>
+#include <qrawfont.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFontEngineGlyphCache;
+class QGLTextureGlyphCache;
+class QFontEngine;
+class Geometry;
+class QSGTextMaskMaterial: public QSGMaterial
+{
+public:
+ QSGTextMaskMaterial(const QRawFont &font);
+ ~QSGTextMaskMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setColor(const QColor &color) { m_color = color; }
+ const QColor &color() const { return m_color; }
+
+ QSGTexture *texture() const { return m_texture; }
+
+ int cacheTextureWidth() const;
+ int cacheTextureHeight() const;
+
+ bool ensureUpToDate();
+
+ QGLTextureGlyphCache *glyphCache() const;
+ void populate(const QPointF &position,
+ const QVector<quint32> &glyphIndexes, const QVector<QPointF> &glyphPositions,
+ QSGGeometry *geometry, QRectF *boundingRect, QPointF *baseLine);
+
+private:
+ void init();
+
+ QSGPlainTexture *m_texture;
+ QExplicitlySharedDataPointer<QFontEngineGlyphCache> m_glyphCache;
+ QRawFont m_font;
+ QColor m_color;
+ QSize m_size;
+};
+
+QT_END_NAMESPACE
+
+#endif // TEXTMASKMATERIAL_H
diff --git a/src/declarative/scenegraph/qsgdefaultimagenode.cpp b/src/declarative/scenegraph/qsgdefaultimagenode.cpp
new file mode 100644
index 0000000000..aa30d009da
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultimagenode.cpp
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultimagenode_p.h"
+
+#include <private/qsgtextureprovider_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultImageNode::QSGDefaultImageNode()
+ : m_sourceRect(0, 0, 1, 1)
+ , m_dirtyGeometry(false)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+{
+ setMaterial(&m_materialO);
+ setOpaqueMaterial(&m_material);
+ setGeometry(&m_geometry);
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("image");
+#endif
+}
+
+void QSGDefaultImageNode::setTargetRect(const QRectF &rect)
+{
+ if (rect == m_targetRect)
+ return;
+ m_targetRect = rect;
+ m_dirtyGeometry = true;
+}
+
+void QSGDefaultImageNode::setSourceRect(const QRectF &rect)
+{
+ if (rect == m_sourceRect)
+ return;
+ m_sourceRect = rect;
+ m_dirtyGeometry = true;
+}
+
+
+void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.filtering() == filtering)
+ return;
+
+ m_material.setFiltering(filtering);
+ m_materialO.setFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+
+void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
+{
+ if (m_material.mipmapFiltering() == filtering)
+ return;
+
+ m_material.setMipmapFiltering(filtering);
+ m_materialO.setMipmapFiltering(filtering);
+ markDirty(DirtyMaterial);
+}
+
+void QSGDefaultImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
+{
+ if (m_material.verticalWrapMode() == wrapMode)
+ return;
+
+ m_material.setVerticalWrapMode(wrapMode);
+ m_materialO.setVerticalWrapMode(wrapMode);
+ markDirty(DirtyMaterial);
+}
+
+void QSGDefaultImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
+{
+ if (m_material.horizontalWrapMode() == wrapMode)
+ return;
+
+ m_material.setHorizontalWrapMode(wrapMode);
+ m_materialO.setHorizontalWrapMode(wrapMode);
+ markDirty(DirtyMaterial);
+}
+
+
+void QSGDefaultImageNode::setTexture(QSGTexture *texture)
+{
+ if (texture == m_material.texture())
+ return;
+
+ m_material.setTexture(texture);
+ m_materialO.setTexture(texture);
+ // Texture cleanup
+// if (!texture.isNull())
+// m_material.setBlending(texture->hasAlphaChannel());
+ markDirty(DirtyMaterial);
+
+ // Because the texture can be a different part of the atlas, we need to update it...
+ m_dirtyGeometry = true;
+}
+
+void QSGDefaultImageNode::update()
+{
+ if (m_dirtyGeometry)
+ updateGeometry();
+}
+
+void QSGDefaultImageNode::preprocess()
+{
+ bool doDirty = false;
+ QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(m_material.texture());
+ if (t) {
+ doDirty = t->updateTexture();
+ updateGeometry();
+ }
+// ### texture cleanup
+// bool alpha = m_material.blending();
+// if (!m_material->texture().isNull() && alpha != m_material.texture()->hasAlphaChannel()) {
+// m_material.setBlending(!alpha);
+// doDirty = true;
+// }
+
+ if (doDirty)
+ markDirty(DirtyMaterial);
+}
+
+void QSGDefaultImageNode::updateGeometry()
+{
+ const QSGTexture *t = m_material.texture();
+ if (!t) {
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry, QRectF(), QRectF());
+ } else {
+ QRectF textureRect = t->textureSubRect();
+ QRectF sr(textureRect.x() + m_sourceRect.x() * textureRect.width(),
+ textureRect.y() + m_sourceRect.y() * textureRect.height(),
+ m_sourceRect.width() * textureRect.width(),
+ m_sourceRect.height() * textureRect.height());
+
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr);
+ }
+ markDirty(DirtyGeometry);
+ m_dirtyGeometry = false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultimagenode_p.h b/src/declarative/scenegraph/qsgdefaultimagenode_p.h
new file mode 100644
index 0000000000..8eb2c89a2a
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultimagenode_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef DEFAULT_PIXMAPNODE_H
+#define DEFAULT_PIXMAPNODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+
+#include "qsgtexturematerial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGDefaultImageNode : public QSGImageNode
+{
+public:
+ QSGDefaultImageNode();
+ virtual void setTargetRect(const QRectF &rect);
+ virtual void setSourceRect(const QRectF &rect);
+ virtual void setTexture(QSGTexture *t);
+ virtual void update();
+
+ virtual void setMipmapFiltering(QSGTexture::Filtering filtering);
+ virtual void setFiltering(QSGTexture::Filtering filtering);
+ virtual void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode);
+ virtual void setVerticalWrapMode(QSGTexture::WrapMode wrapMode);
+
+ virtual void preprocess();
+
+private:
+ void updateGeometry();
+
+ QRectF m_targetRect;
+ QRectF m_sourceRect;
+
+ QSGTextureMaterial m_material;
+ QSGTextureMaterialWithOpacity m_materialO;
+
+ uint m_dirtyGeometry : 1;
+
+ QSGGeometry m_geometry;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp b/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp
new file mode 100644
index 0000000000..a0220cef1f
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultrectanglenode.cpp
@@ -0,0 +1,550 @@
+
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+
+#include "qsgdefaultrectanglenode_p.h"
+
+#include <private/qsgvertexcolormaterial_p.h>
+#include "qsgtexturematerial.h"
+
+#include <private/qsgcontext_p.h>
+
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDefaultRectangleNode::QSGDefaultRectangleNode(QSGContext *context)
+ : m_border(0)
+ , m_radius(0)
+ , m_pen_width(0)
+ , m_gradient_is_opaque(true)
+ , m_dirty_geometry(false)
+ , m_default_geometry(QSGGeometry::defaultAttributes_Point2D(), 4)
+ , m_context(context)
+{
+ setGeometry(&m_default_geometry);
+ setMaterial(&m_fill_material);
+ m_border_material.setColor(QColor(0, 0, 0));
+
+ m_material_type = TypeFlat;
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("rectangle");
+#endif
+}
+
+QSGDefaultRectangleNode::~QSGDefaultRectangleNode()
+{
+ switch (m_material_type) {
+ case TypeFlat:
+ break;
+ case TypeVertexGradient:
+ delete material();
+ break;
+ }
+ delete m_border;
+}
+
+QSGGeometryNode *QSGDefaultRectangleNode::border()
+{
+ if (!m_border) {
+ m_border = new QSGGeometryNode;
+ m_border->setMaterial(&m_border_material);
+ QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 0);
+ m_border->setGeometry(geometry);
+ m_border->setFlag(QSGNode::OwnsGeometry);
+ }
+ return m_border;
+}
+
+void QSGDefaultRectangleNode::setRect(const QRectF &rect)
+{
+ if (rect == m_rect)
+ return;
+ m_rect = rect;
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultRectangleNode::setColor(const QColor &color)
+{
+ if (color == m_fill_material.color())
+ return;
+ if (m_gradient_stops.isEmpty()) {
+ Q_ASSERT(m_material_type == TypeFlat);
+ m_fill_material.setColor(color);
+ setMaterial(&m_fill_material); // Indicate that the material state has changed.
+ }
+}
+
+void QSGDefaultRectangleNode::setPenColor(const QColor &color)
+{
+ if (color == m_border_material.color())
+ return;
+ m_border_material.setColor(color);
+ border()->setMaterial(&m_border_material); // Indicate that the material state has changed.
+}
+
+void QSGDefaultRectangleNode::setPenWidth(qreal width)
+{
+ if (width == m_pen_width)
+ return;
+ m_pen_width = width;
+ QSGNode *b = border();
+ if (m_pen_width <= 0 && b->parent())
+ removeChildNode(b);
+ else if (m_pen_width > 0 && !b->parent())
+ appendChildNode(b);
+ m_dirty_geometry = true;
+}
+
+
+void QSGDefaultRectangleNode::setGradientStops(const QGradientStops &stops)
+{
+ if (stops.constData() == m_gradient_stops.constData())
+ return;
+
+ m_gradient_stops = stops;
+
+ m_gradient_is_opaque = true;
+ for (int i = 0; i < stops.size(); ++i)
+ m_gradient_is_opaque &= stops.at(i).second.alpha() == 0xff;
+
+ if (stops.isEmpty()) {
+ // No gradient specified, use flat color.
+ if (m_material_type != TypeFlat) {
+
+ delete material();
+ delete opaqueMaterial();
+ setOpaqueMaterial(0);
+
+ setMaterial(&m_fill_material);
+ m_material_type = TypeFlat;
+
+ setGeometry(&m_default_geometry);
+ setFlag(OwnsGeometry, false);
+ }
+ } else {
+ if (m_material_type == TypeFlat) {
+ QSGVertexColorMaterial *material = new QSGVertexColorMaterial;
+ setMaterial(material);
+ m_material_type = TypeVertexGradient;
+ QSGGeometry *g = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0);
+ setGeometry(g);
+ setFlag(OwnsGeometry);
+ }
+ static_cast<QSGVertexColorMaterial *>(material())->setOpaque(m_gradient_is_opaque);
+ }
+
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultRectangleNode::setRadius(qreal radius)
+{
+ if (radius == m_radius)
+ return;
+ m_radius = radius;
+ m_dirty_geometry = true;
+}
+
+void QSGDefaultRectangleNode::update()
+{
+ if (m_dirty_geometry) {
+ updateGeometry();
+ m_dirty_geometry = false;
+ }
+}
+
+struct Color4ub
+{
+ unsigned char r, g, b, a;
+};
+
+Color4ub operator *(Color4ub c, float t) { c.a *= t; c.r *= t; c.g *= t; c.b *= t; return c; }
+Color4ub operator +(Color4ub a, Color4ub b) { a.a += b.a; a.r += b.r; a.g += b.g; a.b += b.b; return a; }
+
+static inline Color4ub colorToColor4ub(const QColor &c)
+{
+ Color4ub color = { c.redF() * c.alphaF() * 255,
+ c.greenF() * c.alphaF() * 255,
+ c.blueF() * c.alphaF() * 255,
+ c.alphaF() * 255
+ };
+ return color;
+}
+
+struct Vertex
+{
+ QVector2D position;
+};
+
+struct ColorVertex
+{
+ QVector2D position;
+ Color4ub color;
+};
+
+void QSGDefaultRectangleNode::updateGeometry()
+{
+ // fast path for the simple case...
+ if ((m_pen_width == 0 || m_border_material.color().alpha() == 0)
+ && m_radius == 0
+ && m_material_type == TypeFlat) {
+ QSGGeometry::updateRectGeometry(&m_default_geometry, m_rect);
+ return;
+ }
+
+
+ // ### This part down below is not optimal, using QVectors and reallocation for
+ // every change, but its all going to be fixed up in rewrite...
+
+ QSGGeometry *fill = geometry();
+
+ // Check that the vertex type matches the material.
+ Q_ASSERT(m_material_type != TypeFlat || fill->stride() == sizeof(Vertex));
+ Q_ASSERT(m_material_type != TypeVertexGradient || fill->stride() == sizeof(ColorVertex));
+
+ QSGGeometry *borderGeometry = 0;
+ if (m_border) {
+ borderGeometry = border()->geometry();
+ Q_ASSERT(borderGeometry->stride() == sizeof(QSGGeometry::Point2D));
+ }
+
+ int fillVertexCount = 0;
+ int borderVertexCount = 0;
+ int borderIndexCount = 0;
+
+ QVector<uchar> fillVertexData;
+ QVector<Vertex> borderVertexData;
+ QVector<ushort> borderIndexData;
+
+ Color4ub fillColor = colorToColor4ub(m_fill_material.color());
+ const QGradientStops &stops = m_gradient_stops;
+
+ if (m_radius > 0) {
+ // Rounded corners.
+
+ // Radius should never exceeds half of the width or half of the height
+ qreal radius = qMin(qMin(m_rect.width() / 2, m_rect.height() / 2), m_radius);
+ QRectF innerRect = m_rect;
+ innerRect.adjust(radius, radius, -radius, -radius);
+ if (m_pen_width & 1) {
+ // Pen width is odd, so add the offset as documented.
+ innerRect.moveLeft(innerRect.left() + qreal(0.5));
+ innerRect.moveTop(innerRect.top() + qreal(0.5));
+ }
+
+ qreal innerRadius = radius - m_pen_width * qreal(0.5);
+ qreal outerRadius = radius + m_pen_width * qreal(0.5);
+
+ int segments = qMin(30, qCeil(outerRadius)); // Number of segments per corner.
+
+ /*
+
+ --+-__
+ | segment
+ | _+
+ --+-__ _- \
+ -+ segment
+ --------+ \ <- gradient line
+ +-----+
+ | |
+
+ */
+
+ // Overestimate the number of vertices and indices, reduce afterwards when the actual numbers are known.
+ if (m_pen_width) {
+ // The reason I add extra vertices where the gradient lines intersect the border is
+ // to avoid pixel sized gaps between the fill and the border caused by floating point
+ // inaccuracies.
+ borderVertexData.resize((segments + 1) * 2 * 4 + m_gradient_stops.size() * 2);
+ }
+ fillVertexData.resize(((segments + 1) * 4 + m_gradient_stops.size() * 2) * fill->stride());
+
+ Vertex *borderVertices = borderVertexData.data();
+ void *fillVertices = fillVertexData.data(); // Can be Vertex, ColorVertex or TextureVertex.
+
+
+ int nextGradientStop = 0;
+ qreal gradientPos = (radius - innerRadius) / (innerRect.height() + 2 * radius);
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
+ ++nextGradientStop;
+
+ qreal py = 0; // previous inner y-coordinate.
+ qreal plx = 0; // previous inner left x-coordinate.
+ qreal prx = 0; // previous inner right x-coordinate.
+
+ for (int part = 0; part < 2; ++part) {
+ for (int i = 0; i <= segments; ++i) {
+ //### Should change to calculate sin/cos only once.
+ qreal angle = qreal(0.5 * M_PI) * (part + i / qreal(segments));
+ qreal s = qFastSin(angle);
+ qreal c = qFastCos(angle);
+ qreal y = (part ? innerRect.bottom() : innerRect.top()) - innerRadius * c; // current inner y-coordinate.
+ qreal lx = innerRect.left() - innerRadius * s; // current inner left x-coordinate.
+ qreal rx = innerRect.right() + innerRadius * s; // current inner right x-coordinate.
+ qreal Y = (part ? innerRect.bottom() : innerRect.top()) - outerRadius * c; // current outer y-coordinate.
+ qreal lX = innerRect.left() - outerRadius * s; // current outer left x-coordinate.
+ qreal rX = innerRect.right() + outerRadius * s; // current outer right x-coordinate.
+
+ gradientPos = ((part ? innerRect.height() : 0) + radius - innerRadius * c) / (innerRect.height() + 2 * radius);
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos) {
+ // Insert vertices at gradient stops.
+ qreal gy = (innerRect.top() - radius) + stops.at(nextGradientStop).first * (innerRect.height() + 2 * radius);
+ Q_ASSERT(fillVertexCount >= 2);
+ qreal t = (gy - py) / (y - py);
+ qreal glx = plx * (1 - t) + t * lx;
+ qreal grx = prx * (1 - t) + t * rx;
+
+ if (m_pen_width) {
+ borderVertices[borderVertexCount++].position = QVector2D(grx, gy);
+ borderVertices[borderVertexCount++].position = QVector2D(glx, gy);
+
+ int first = borderIndexData.first();
+ borderIndexData.prepend(borderVertexCount - 1);
+ borderIndexData.prepend(first);
+
+ int last = borderIndexData.at(borderIndexData.size() - 2);
+ borderIndexData.append(last);
+ borderIndexData.append(borderVertexCount - 2);
+ }
+
+ Q_ASSERT(QSGVertexColorMaterial::is(material()));
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+
+ fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
+ vertices[fillVertexCount].position = QVector2D(grx, gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(glx, gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+
+ ++nextGradientStop;
+ }
+
+ if (m_pen_width) {
+ borderVertices[borderVertexCount++].position = QVector2D(rX, Y);
+ borderVertices[borderVertexCount++].position = QVector2D(lX, Y);
+ borderVertices[borderVertexCount++].position = QVector2D(rx, y);
+ borderVertices[borderVertexCount++].position = QVector2D(lx, y);
+
+ borderIndexData.prepend(borderVertexCount - 1);
+ borderIndexData.prepend(borderVertexCount - 3);
+ borderIndexData.append(borderVertexCount - 4);
+ borderIndexData.append(borderVertexCount - 2);
+ }
+
+ if (stops.isEmpty()) {
+ Q_ASSERT(m_material_type == TypeFlat);
+ Vertex *vertices = (Vertex *)fillVertices;
+ vertices[fillVertexCount++].position = QVector2D(rx, y);
+ vertices[fillVertexCount++].position = QVector2D(lx, y);
+ } else {
+ if (nextGradientStop == 0) {
+ fillColor = colorToColor4ub(stops.at(0).second);
+ } else if (nextGradientStop == stops.size()) {
+ fillColor = colorToColor4ub(stops.last().second);
+ } else {
+ const QGradientStop &prev = stops.at(nextGradientStop - 1);
+ const QGradientStop &next = stops.at(nextGradientStop);
+ qreal t = (gradientPos - prev.first) / (next.first - prev.first);
+ fillColor = (colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t);
+ }
+
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+ vertices[fillVertexCount].position = QVector2D(rx, y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(lx, y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ }
+
+ py = y;
+ plx = lx;
+ prx = rx;
+ }
+ }
+
+
+ if (m_pen_width) {
+ // Close border.
+ ushort first = borderIndexData.at(0);
+ ushort second = borderIndexData.at(1);
+ borderIndexData.append(first);
+ borderIndexData.append(second);
+
+ borderIndexCount = borderIndexData.size();
+ }
+
+ } else {
+
+ // Straight corners.
+ QRectF innerRect = m_rect;
+ QRectF outerRect = m_rect;
+
+ qreal halfPenWidth = 0;
+ if (m_pen_width) {
+ if (m_pen_width & 1) {
+ // Pen width is odd, so add the offset as documented.
+ innerRect.moveLeft(innerRect.left() + qreal(0.5));
+ innerRect.moveTop(innerRect.top() + qreal(0.5));
+ outerRect = innerRect;
+ }
+ halfPenWidth = m_pen_width * qreal(0.5);
+ innerRect.adjust(halfPenWidth, halfPenWidth, -halfPenWidth, -halfPenWidth);
+ outerRect.adjust(-halfPenWidth, -halfPenWidth, halfPenWidth, halfPenWidth);
+ }
+
+ if (m_pen_width) {
+ borderVertexData.resize((2 + stops.size()) * 2 + 4);
+ borderIndexData.resize((2 + stops.size()) * 2 * 2 + 4);
+ }
+ fillVertexData.resize((2 + stops.size()) * 2 * fill->stride());
+
+ void *fillVertices = fillVertexData.data();
+ Vertex *borderVertices = (Vertex *) borderVertexData.data();
+ ushort *borderIndices = borderIndexData.data();
+
+ int nextGradientStop = 0;
+ qreal gradientPos = halfPenWidth / m_rect.height();
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos)
+ ++nextGradientStop;
+
+ for (int part = 0; part < 2; ++part) {
+ qreal y = (part ? innerRect.bottom() : innerRect.top());
+ gradientPos = (y - innerRect.top() + halfPenWidth) / m_rect.height();
+
+ while (nextGradientStop < stops.size() && stops.at(nextGradientStop).first <= gradientPos) {
+ // Insert vertices at gradient stops.
+ qreal gy = (innerRect.top() - halfPenWidth) + stops.at(nextGradientStop).first * m_rect.height();
+ Q_ASSERT(fillVertexCount >= 2);
+
+ Q_ASSERT(QSGVertexColorMaterial::is(material()));
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+
+ fillColor = colorToColor4ub(stops.at(nextGradientStop).second);
+ vertices[fillVertexCount].position = QVector2D(innerRect.right(), gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(innerRect.left(), gy);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+
+ if (m_pen_width) {
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.right(), gy);
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.left(), gy);
+ }
+
+ ++nextGradientStop;
+ }
+
+ if (stops.isEmpty()) {
+ Q_ASSERT(m_material_type == TypeFlat);
+ Vertex *vertices = (Vertex *)fillVertices;
+ vertices[fillVertexCount++].position = QVector2D(innerRect.right(), y);
+ vertices[fillVertexCount++].position = QVector2D(innerRect.left(), y);
+ } else {
+ if (nextGradientStop == 0) {
+ fillColor = colorToColor4ub(stops.at(0).second);
+ } else if (nextGradientStop == stops.size()) {
+ fillColor = colorToColor4ub(stops.last().second);
+ } else {
+ const QGradientStop &prev = stops.at(nextGradientStop - 1);
+ const QGradientStop &next = stops.at(nextGradientStop);
+ qreal t = (gradientPos - prev.first) / (next.first - prev.first);
+ fillColor = (colorToColor4ub(prev.second) * (1 - t) + colorToColor4ub(next.second) * t);
+ }
+
+ ColorVertex *vertices = (ColorVertex *)fillVertices;
+ vertices[fillVertexCount].position = QVector2D(innerRect.right(), y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ vertices[fillVertexCount].position = QVector2D(innerRect.left(), y);
+ vertices[fillVertexCount].color = fillColor;
+ ++fillVertexCount;
+ }
+
+ if (m_pen_width) {
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.right(), y);
+ borderVertices[borderVertexCount++].position = QVector2D(innerRect.left(), y);
+ }
+ }
+
+ if (m_pen_width) {
+ // Add four corners.
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.right(), outerRect.top());
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.left(), outerRect.top());
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.right(), outerRect.bottom());
+ borderVertices[borderVertexCount++].position = QVector2D(outerRect.left(), outerRect.bottom());
+
+ for (int i = 0; i < fillVertexCount / 2; ++i) {
+ borderIndices[borderIndexCount++] = borderVertexCount - (i == 0 ? 4 : 2); // Upper or lower right corner.
+ borderIndices[borderIndexCount++] = 2 * i + 0;
+ }
+ for (int i = 0; i < fillVertexCount / 2; ++i) {
+ borderIndices[borderIndexCount++] = borderVertexCount - (i == 0 ? 1 : 3); // Lower or upper left corner.
+ borderIndices[borderIndexCount++] = fillVertexCount - 2 * i - 1;
+ }
+ borderIndices[borderIndexCount++] = fillVertexCount; // Upper right corner.
+ borderIndices[borderIndexCount++] = 0;
+ Q_ASSERT(fillVertexCount + 4 == borderVertexCount);
+ }
+ }
+
+ // Copy from temporary datastructures to geometry...
+ if (m_pen_width) {
+ borderGeometry->allocate(borderVertexCount, borderIndexCount);
+ memcpy(borderGeometry->indexData(), borderIndexData.constData(), borderIndexCount * sizeof(quint16));
+ memcpy(borderGeometry->vertexData(), borderVertexData.constData(), borderVertexCount * sizeof(Vertex));
+ m_border->markDirty(DirtyGeometry);
+ }
+
+ fill->allocate(fillVertexCount);
+ memcpy(fill->vertexData(), fillVertexData.constData(), fillVertexCount * fill->stride());
+
+ markDirty(DirtyGeometry);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultrectanglenode_p.h b/src/declarative/scenegraph/qsgdefaultrectanglenode_p.h
new file mode 100644
index 0000000000..3bf14947de
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultrectanglenode_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef DEFAULT_RECTANGLENODE_H
+#define DEFAULT_RECTANGLENODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+
+#include "qsgflatcolormaterial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGMaterial;
+class QSGContext;
+
+class QSGDefaultRectangleNode : public QSGRectangleNode
+{
+public:
+ QSGDefaultRectangleNode(QSGContext *context);
+ ~QSGDefaultRectangleNode();
+
+ virtual void setRect(const QRectF &rect);
+ virtual void setColor(const QColor &color);
+ virtual void setPenColor(const QColor &color);
+ virtual void setPenWidth(qreal width);
+ virtual void setGradientStops(const QGradientStops &stops);
+ virtual void setRadius(qreal radius);
+ virtual void update();
+
+private:
+ enum {
+ TypeFlat,
+ TypeVertexGradient
+ };
+ QSGGeometryNode *border();
+
+ void updateGeometry();
+ void updateGradientTexture();
+
+ QSGGeometryNode *m_border;
+ QSGFlatColorMaterial m_border_material;
+ QSGFlatColorMaterial m_fill_material;
+
+ QRectF m_rect;
+ QGradientStops m_gradient_stops;
+ qreal m_radius;
+ int m_pen_width;
+
+ uint m_gradient_is_opaque : 1;
+ uint m_dirty_geometry : 1;
+
+ uint m_material_type : 2; // Only goes up to 3
+
+ QSGGeometry m_default_geometry;
+
+ QSGContext *m_context;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp
new file mode 100644
index 0000000000..5801311be4
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp
@@ -0,0 +1,939 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdistancefieldglyphcache_p.h"
+
+#include <qmath.h>
+#include <private/qtriangulator_p.h>
+#include <private/qdeclarativeglobal_p.h>
+#include <qglshaderprogram.h>
+#include <private/qglengineshadersource_p.h>
+#include <private/qsgcontext_p.h>
+#include <private/qrawfont_p.h>
+#include <qglfunctions.h>
+#include <qglyphs.h>
+#include <qrawfont.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 \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE * 2 : \
+ QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE)
+#define QT_DISTANCEFIELD_TILESIZE \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_TILESIZE * 2 : \
+ QT_DISTANCEFIELD_DEFAULT_TILESIZE)
+#define QT_DISTANCEFIELD_SCALE \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_SCALE / 2 : \
+ QT_DISTANCEFIELD_DEFAULT_SCALE)
+#define QT_DISTANCEFIELD_RADIUS \
+ (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_RADIUS / 2 : \
+ QT_DISTANCEFIELD_DEFAULT_RADIUS)
+
+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;
+}
+
+struct DFPoint
+{
+ float x, y;
+};
+
+struct DFVertex
+{
+ DFPoint p;
+ float d;
+};
+
+static void drawRectangle(float *bits, int width, int height, const DFVertex *v1, const DFVertex *v2, const DFVertex *v3, const DFVertex *v4)
+{
+ float minY = qMin(qMin(v1->p.y, v2->p.y), qMin(v3->p.y, v4->p.y));
+ if (v2->p.y == minY) {
+ const DFVertex *tmp = v1;
+ v1 = v2;
+ v2 = v3;
+ v3 = v4;
+ v4 = tmp;
+ } else if (v3->p.y == minY) {
+ const DFVertex *tmp1 = v1;
+ const DFVertex *tmp2 = v2;
+ v1 = v3;
+ v2 = v4;
+ v3 = tmp1;
+ v4 = tmp2;
+ } else if (v4->p.y == minY) {
+ const DFVertex *tmp = v4;
+ v4 = v3;
+ v3 = v2;
+ v2 = v1;
+ v1 = tmp;
+ }
+
+ /*
+ v1
+ / \
+ v4 v2
+ \ /
+ v3
+ */
+
+ int fromY = qMax(0, qCeil(v1->p.y));
+ int midY1 = qMin(height, qCeil(qMin(v2->p.y, v4->p.y)));
+ int midY2 = qMin(height, qCeil(qMax(v2->p.y, v4->p.y)));
+ int toY = qMin(height, qCeil(v3->p.y));
+
+ if (toY <= fromY)
+ return;
+
+ bits += width * fromY;
+ int y = fromY;
+
+ float leftDx = (v4->p.x - v1->p.x) / (v4->p.y - v1->p.y);
+ float leftDd = (v4->d - v1->d) / (v4->p.y - v1->p.y);
+ float leftX = v1->p.x + (fromY - v1->p.y) * leftDx;
+ float leftD = v1->d + (fromY - v1->p.y) * leftDd;
+
+ float rightDx = (v2->p.x - v1->p.x) / (v2->p.y - v1->p.y);
+ float rightDd = (v2->d - v1->d) / (v2->p.y - v1->p.y);
+ float rightX = v1->p.x + (fromY - v1->p.y) * rightDx;
+ float rightD = v1->d + (fromY - v1->p.y) * rightDd;
+
+ float dd = ((v2->d - v1->d) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->d - v1->d))
+ / ((v2->p.x - v1->p.x) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->p.x - v1->p.x));
+
+ for (; y < midY1; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+
+ if (midY1 == toY)
+ return;
+
+ if (v2->p.y > v4->p.y) {
+ // Long right edge.
+ leftDx = (v3->p.x - v4->p.x) / (v3->p.y - v4->p.y);
+ leftDd = (v3->d - v4->d) / (v3->p.y - v4->p.y);
+ leftX = v4->p.x + (midY1 - v4->p.y) * leftDx;
+ leftD = v4->d + (midY1 - v4->p.y) * leftDd;
+ } else {
+ // Long left edge.
+ rightDx = (v3->p.x - v2->p.x) / (v3->p.y - v2->p.y);
+ rightDd = (v3->d - v2->d) / (v3->p.y - v2->p.y);
+ rightX = v2->p.x + (midY1 - v2->p.y) * rightDx;
+ rightD = v2->d + (midY1 - v2->p.y) * rightDd;
+ }
+
+ for (; y < midY2; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+
+ if (midY2 == toY)
+ return;
+
+ if (v2->p.y > v4->p.y) {
+ // Long left edge.
+ rightDx = (v3->p.x - v2->p.x) / (v3->p.y - v2->p.y);
+ rightDd = (v3->d - v2->d) / (v3->p.y - v2->p.y);
+ rightX = v2->p.x + (midY2 - v2->p.y) * rightDx;
+ rightD = v2->d + (midY2 - v2->p.y) * rightDd;
+ } else {
+ // Long right edge.
+ leftDx = (v3->p.x - v4->p.x) / (v3->p.y - v4->p.y);
+ leftDd = (v3->d - v4->d) / (v3->p.y - v4->p.y);
+ leftX = v4->p.x + (midY2 - v4->p.y) * leftDx;
+ leftD = v4->d + (midY2 - v4->p.y) * leftDd;
+ }
+
+ for (; y < toY; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+}
+
+static void drawTriangle(float *bits, int width, int height, const DFVertex *v1, const DFVertex *v2, const DFVertex *v3)
+{
+ float minY = qMin(qMin(v1->p.y, v2->p.y), v3->p.y);
+ if (v2->p.y == minY) {
+ const DFVertex *tmp = v1;
+ v1 = v2;
+ v2 = v3;
+ v3 = tmp;
+ } else if (v3->p.y == minY) {
+ const DFVertex *tmp = v3;
+ v3 = v2;
+ v2 = v1;
+ v1 = tmp;
+ }
+
+ // v1
+ // / \
+ // v3--v2
+
+ int fromY = qMax(0, qCeil(v1->p.y));
+ int midY = qMin(height, qCeil(qMin(v2->p.y, v3->p.y)));
+ int toY = qMin(height, qCeil(qMax(v2->p.y, v3->p.y)));
+
+ if (toY <= fromY)
+ return;
+
+ float leftDx = (v3->p.x - v1->p.x) / (v3->p.y - v1->p.y);
+ float leftDd = (v3->d - v1->d) / (v3->p.y - v1->p.y);
+ float leftX = v1->p.x + (fromY - v1->p.y) * leftDx;
+ float leftD = v1->d + (fromY - v1->p.y) * leftDd;
+
+ float rightDx = (v2->p.x - v1->p.x) / (v2->p.y - v1->p.y);
+ float rightDd = (v2->d - v1->d) / (v2->p.y - v1->p.y);
+ float rightX = v1->p.x + (fromY - v1->p.y) * rightDx;
+ float rightD = v1->d + (fromY - v1->p.y) * rightDd;
+
+ float dd = ((v2->d - v1->d) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->d - v1->d))
+ / ((v2->p.x - v1->p.x) * (v3->p.y - v1->p.y) - (v2->p.y - v1->p.y) * (v3->p.x - v1->p.x));
+
+ bits += width * fromY;
+ int y = fromY;
+ for (; y < midY; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+
+ if (midY == toY)
+ return;
+
+ if (v2->p.y > v3->p.y) {
+ // Long right edge.
+ leftDx = (v2->p.x - v3->p.x) / (v2->p.y - v3->p.y);
+ leftDd = (v2->d - v3->d) / (v2->p.y - v3->p.y);
+ leftX = v3->p.x + (midY - v3->p.y) * leftDx;
+ leftD = v3->d + (midY - v3->p.y) * leftDd;
+ } else {
+ // Long left edge.
+ rightDx = (v3->p.x - v2->p.x) / (v3->p.y - v2->p.y);
+ rightDd = (v3->d - v2->d) / (v3->p.y - v2->p.y);
+ rightX = v2->p.x + (midY - v2->p.y) * rightDx;
+ rightD = v2->d + (midY - v2->p.y) * rightDd;
+ }
+
+ for (; y < toY; ++y, leftX += leftDx, leftD += leftDd, rightX += rightDx, rightD += rightDd, bits += width) {
+ int fromX = qMax(0, qCeil(leftX));
+ int toX = qMin(width, qCeil(rightX));
+ if (toX <= fromX)
+ continue;
+ float d = leftD + (fromX - leftX) * dd;
+ for (int x = fromX; x < toX; ++x, d += dd) {
+ if (abs(d) < abs(bits[x]))
+ bits[x] = d;
+ }
+ }
+}
+
+static QImage makeDistanceField(int imgSize, const QPainterPath &path, int dfScale, float offs)
+{
+ QImage image(imgSize, imgSize, QImage::Format_ARGB32_Premultiplied);
+
+ if (path.isEmpty()) {
+ image.fill(0);
+ return image;
+ }
+
+ QPolylineSet polys = qPolyline(path);
+
+ union Pacific {
+ float value;
+ QRgb color;
+ };
+ Pacific interior;
+ Pacific exterior;
+ interior.value = 127;
+ exterior.value = -127;
+
+ image.fill(exterior.color);
+
+ QPainter p(&image);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.translate(offs, offs);
+ p.scale(1 / qreal(dfScale), 1 / qreal(dfScale));
+ p.fillPath(path, QColor::fromRgba(interior.color));
+ p.end();
+
+ float *bits = (float *)image.bits();
+ const float angleStep = 15 * 3.141592653589793238f / 180;
+ const DFPoint rotation = { cos(angleStep), sin(angleStep) };
+
+ bool isShortData = polys.indices.type() == QVertexIndexVector::UnsignedShort;
+ const void *indices = polys.indices.data();
+ int index = 0;
+ QVector<DFPoint> normals;
+ QVector<DFVertex> vertices;
+ normals.reserve(polys.vertices.count());
+ vertices.reserve(polys.vertices.count());
+
+ while (index < polys.indices.size()) {
+ normals.clear();
+ vertices.clear();
+
+ // Find end of polygon.
+ int end = index;
+ if (isShortData) {
+ while (((quint16 *)indices)[end] != quint16(-1))
+ ++end;
+ } else {
+ while (((quint32 *)indices)[end] != quint32(-1))
+ ++end;
+ }
+
+ // Calculate vertex normals.
+ for (int next = index, prev = end - 1; next < end; prev = next++) {
+ quint32 fromVertexIndex = isShortData ? (quint32)((quint16 *)indices)[prev] : ((quint32 *)indices)[prev];
+ quint32 toVertexIndex = isShortData ? (quint32)((quint16 *)indices)[next] : ((quint32 *)indices)[next];
+ const qreal *from = &polys.vertices.at(fromVertexIndex * 2);
+ const qreal *to = &polys.vertices.at(toVertexIndex * 2);
+ DFPoint n;
+ n.x = float(to[1] - from[1]);
+ n.y = float(from[0] - to[0]);
+ if (n.x == 0 && n.y == 0)
+ continue;
+ float scale = offs / sqrt(n.x * n.x + n.y * n.y);
+ n.x *= scale;
+ n.y *= scale;
+ normals.append(n);
+
+ DFVertex v;
+ v.p.x = float(to[0] / dfScale) + offs - 0.5f;
+ v.p.y = float(to[1] / dfScale) + offs - 0.5f;
+ v.d = 0.0f;
+ vertices.append(v);
+ }
+
+ QVector<bool> isConvex(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++) {
+ DFPoint n = normals.at(next);
+ DFVertex intPrev = vertices.at(prev);
+ DFVertex extPrev = vertices.at(prev);
+ DFVertex intNext = vertices.at(next);
+ DFVertex extNext = vertices.at(next);
+
+ extPrev.p.x += n.x;
+ extPrev.p.y += n.y;
+ intPrev.p.x -= n.x;
+ intPrev.p.y -= n.y;
+ extNext.p.x += n.x;
+ extNext.p.y += n.y;
+ intNext.p.x -= n.x;
+ intNext.p.y -= n.y;
+ extPrev.d = 127;
+ extNext.d = 127;
+ intPrev.d = -127;
+ intNext.d = -127;
+
+ drawRectangle(bits, image.width(), image.height(),
+ &vertices.at(prev), &extPrev, &extNext, &vertices.at(next));
+
+ drawRectangle(bits, image.width(), image.height(),
+ &intPrev, &vertices.at(prev), &vertices.at(next), &intNext);
+
+ if (isConvex.at(prev)) {
+ DFVertex v = extPrev;
+ for (;;) {
+ DFPoint rn = { n.x * rotation.x + n.y * rotation.y,
+ n.y * rotation.x - n.x * rotation.y };
+ n = rn;
+ if (n.x * normals.at(prev).y - n.y * normals.at(prev).x >= -0.001) {
+ v.p.x = vertices.at(prev).p.x + normals.at(prev).x;
+ v.p.y = vertices.at(prev).p.y + normals.at(prev).y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &v, &extPrev);
+ break;
+ }
+
+ v.p.x = vertices.at(prev).p.x + n.x;
+ v.p.y = vertices.at(prev).p.y + n.y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &v, &extPrev);
+ extPrev = v;
+ }
+ } else {
+ DFVertex v = intPrev;
+ for (;;) {
+ DFPoint rn = { n.x * rotation.x - n.y * rotation.y,
+ n.y * rotation.x + n.x * rotation.y };
+ n = rn;
+ if (n.x * normals.at(prev).y - n.y * normals.at(prev).x <= 0.001) {
+ v.p.x = vertices.at(prev).p.x - normals.at(prev).x;
+ v.p.y = vertices.at(prev).p.y - normals.at(prev).y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &intPrev, &v);
+ break;
+ }
+
+ v.p.x = vertices.at(prev).p.x - n.x;
+ v.p.y = vertices.at(prev).p.y - n.y;
+ drawTriangle(bits, image.width(), image.height(), &vertices.at(prev), &intPrev, &v);
+ intPrev = v;
+ }
+ }
+ }
+ index = end + 1;
+ }
+
+ for (int y = 0; y < image.height(); ++y) {
+ QRgb *iLine = (QRgb *)image.scanLine(y);
+ float *fLine = (float *)iLine;
+ for (int x = 0; x < image.width(); ++x)
+ iLine[x] = QRgb(fLine[x] + 127.5) << 24;
+ }
+
+ return image;
+}
+
+static void convert_to_Format_Alpha(QImage *image)
+{
+ const int width = image->width();
+ const int height = image->height();
+ uchar *data = image->bits();
+
+ for (int i = 0; i < height; ++i) {
+ uchar *o = data + i * width;
+ for (int x = 0; x < width; ++x)
+ o[x] = (uchar)qAlpha(image->pixel(x, i));
+ }
+}
+
+static bool 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;
+}
+
+DEFINE_BOOL_CONFIG_OPTION(disableDistanceField, QML_DISABLE_DISTANCEFIELD)
+
+QHash<QPair<const QGLContext *, QFontEngine *>, QSGDistanceFieldGlyphCache *> QSGDistanceFieldGlyphCache::m_caches;
+QHash<QFontEngine *, QGLContextGroupResource<QSGDistanceFieldGlyphCache::DistanceFieldTextureData> > QSGDistanceFieldGlyphCache::m_textures_data;
+
+QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCache::get(const QGLContext *ctx, const QRawFont &font)
+{
+ QRawFontPrivate *fontD = QRawFontPrivate::get(font);
+ QPair<const QGLContext *, QFontEngine *> key(ctx, fontD->fontEngine);
+ QHash<QPair<const QGLContext *, QFontEngine *>, QSGDistanceFieldGlyphCache *>::iterator atlas = m_caches.find(key);
+ if (atlas == m_caches.end())
+ atlas = m_caches.insert(key, new QSGDistanceFieldGlyphCache(ctx, font));
+
+ return atlas.value();
+}
+
+QSGDistanceFieldGlyphCache::DistanceFieldTextureData *QSGDistanceFieldGlyphCache::textureData()
+{
+ return m_textures_data[QRawFontPrivate::get(m_font)->fontEngine].value(ctx);
+}
+
+QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(const QGLContext *c, const QRawFont &font)
+ : QObject()
+ , m_maxTextureSize(0)
+ , ctx(c)
+ , m_blitProgram(0)
+{
+ Q_ASSERT(font.isValid());
+ m_font = font;
+
+ m_textureData = textureData();
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ m_glyphCount = fontD->fontEngine->glyphCount();
+
+ m_textureData->doubleGlyphResolution = fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
+
+ m_referenceFont = m_font;
+ m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE);
+ Q_ASSERT(m_referenceFont.isValid());
+
+ m_vertexCoordinateArray[0] = -1.0f;
+ m_vertexCoordinateArray[1] = -1.0f;
+ m_vertexCoordinateArray[2] = 1.0f;
+ m_vertexCoordinateArray[3] = -1.0f;
+ m_vertexCoordinateArray[4] = 1.0f;
+ m_vertexCoordinateArray[5] = 1.0f;
+ m_vertexCoordinateArray[6] = -1.0f;
+ m_vertexCoordinateArray[7] = 1.0f;
+
+ m_textureCoordinateArray[0] = 0.0f;
+ m_textureCoordinateArray[1] = 0.0f;
+ m_textureCoordinateArray[2] = 1.0f;
+ m_textureCoordinateArray[3] = 0.0f;
+ m_textureCoordinateArray[4] = 1.0f;
+ m_textureCoordinateArray[5] = 1.0f;
+ m_textureCoordinateArray[6] = 0.0f;
+ m_textureCoordinateArray[7] = 1.0f;
+
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ this, SLOT(onContextDestroyed(const QGLContext*)));
+}
+
+QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
+{
+ delete m_blitProgram;
+}
+
+void QSGDistanceFieldGlyphCache::onContextDestroyed(const QGLContext *context)
+{
+ if (context != ctx)
+ return;
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ QPair<const QGLContext *, QFontEngine *> key(context, fontD->fontEngine);
+ m_caches.remove(key);
+ deleteLater();
+}
+
+GLuint QSGDistanceFieldGlyphCache::texture()
+{
+ return m_textureData->texture;
+}
+
+QSize QSGDistanceFieldGlyphCache::textureSize() const
+{
+ return m_textureData->size;
+}
+
+int QSGDistanceFieldGlyphCache::maxTextureSize() const
+{
+ if (!m_maxTextureSize)
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
+ return m_maxTextureSize;
+}
+
+QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph)
+{
+ QHash<glyph_t, Metrics>::iterator metric = m_metrics.find(glyph);
+ if (metric == m_metrics.end()) {
+ QPainterPath path = m_font.pathForGlyph(glyph);
+
+ Metrics m;
+ m.width = path.boundingRect().width();
+ m.height = path.boundingRect().height();
+ m.baselineX = path.boundingRect().x();
+ m.baselineY = -path.boundingRect().y();
+
+ metric = m_metrics.insert(glyph, m);
+ }
+
+ return metric.value();
+}
+
+QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph)
+{
+ return m_textureData->texCoords.value(glyph);
+}
+
+QImage QSGDistanceFieldGlyphCache::renderDistanceFieldGlyph(glyph_t glyph) const
+{
+ QRawFont renderFont = m_font;
+ renderFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE * QT_DISTANCEFIELD_SCALE);
+
+ QPainterPath path = renderFont.pathForGlyph(glyph);
+ path.translate(-path.boundingRect().topLeft());
+ path.setFillRule(Qt::WindingFill);
+
+ QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE,
+ path,
+ QT_DISTANCEFIELD_SCALE,
+ QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE));
+ return im;
+}
+
+qreal QSGDistanceFieldGlyphCache::fontScale() const
+{
+ return qreal(m_font.pixelSize()) / QT_DISTANCEFIELD_BASEFONTSIZE;
+}
+
+int QSGDistanceFieldGlyphCache::distanceFieldRadius() const
+{
+ return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE;
+}
+
+void QSGDistanceFieldGlyphCache::populate(int count, const glyph_t *glyphs)
+{
+ for (int i = 0; i < count; ++i) {
+ glyph_t glyphIndex = glyphs[i];
+ if (glyphIndex >= glyphCount()) {
+ qWarning("Warning: distance-field glyph is not available with index %d", glyphIndex);
+ continue;
+ }
+
+ if (++m_textureData->glyphRefCount[glyphIndex] == 1)
+ m_textureData->unusedGlyphs.remove(glyphIndex);
+
+ if (m_textureData->texCoords.contains(glyphIndex)
+ || (cacheIsFull() && m_textureData->unusedGlyphs.isEmpty()))
+ continue;
+
+ QPainterPath path = m_referenceFont.pathForGlyph(glyphIndex);
+ if (path.isEmpty()) {
+ m_textureData->texCoords.insert(glyphIndex, TexCoord());
+ continue;
+ }
+
+ TexCoord c;
+ c.xMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE);
+ c.yMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE);
+ c.x = m_textureData->currX;
+ c.y = m_textureData->currY;
+ c.width = path.boundingRect().width();
+ c.height = path.boundingRect().height();
+
+ if (!cacheIsFull()) {
+ m_textureData->currX += QT_DISTANCEFIELD_TILESIZE;
+ if (m_textureData->currX >= maxTextureSize()) {
+ m_textureData->currX = 0;
+ m_textureData->currY += QT_DISTANCEFIELD_TILESIZE;
+ }
+ } else {
+ // Recycle glyphs
+ if (!m_textureData->unusedGlyphs.isEmpty()) {
+ glyph_t unusedGlyph = *m_textureData->unusedGlyphs.constBegin();
+ TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
+ c.x = unusedCoord.x;
+ c.y = unusedCoord.y;
+ m_textureData->unusedGlyphs.remove(unusedGlyph);
+ m_textureData->texCoords.remove(unusedGlyph);
+ }
+ }
+
+ if (c.y < maxTextureSize()) {
+ m_textureData->texCoords.insert(glyphIndex, c);
+ m_textureData->pendingGlyphs.insert(glyphIndex);
+ }
+ }
+}
+
+void QSGDistanceFieldGlyphCache::derefGlyphs(int count, const glyph_t *glyphs)
+{
+ for (int i = 0; i < count; ++i)
+ if (--m_textureData->glyphRefCount[glyphs[i]] == 0 && !glyphTexCoord(glyphs[i]).isNull())
+ m_textureData->unusedGlyphs.insert(glyphs[i]);
+}
+
+void QSGDistanceFieldGlyphCache::createTexture(int width, int height)
+{
+ if (ctx->d_ptr->workaround_brokenFBOReadBack && m_textureData->image.isNull())
+ m_textureData->image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
+
+ while (glGetError() != GL_NO_ERROR) { }
+
+ glGenTextures(1, &m_textureData->texture);
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ QVarLengthArray<uchar> data(width * height);
+ for (int i = 0; i < data.size(); ++i)
+ data[i] = 0;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ m_textureData->size = QSize(width, height);
+
+ GLuint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures(1, &m_textureData->texture);
+ m_textureData->texture = 0;
+ }
+
+}
+
+void QSGDistanceFieldGlyphCache::resizeTexture(int width, int height)
+{
+ int oldWidth = m_textureData->size.width();
+ int oldHeight = m_textureData->size.height();
+ if (width == oldWidth && height == oldHeight)
+ return;
+
+ GLuint oldTexture = m_textureData->texture;
+ createTexture(width, height);
+
+ if (!oldTexture)
+ return;
+
+ if (ctx->d_ptr->workaround_brokenFBOReadBack) {
+ m_textureData->image = m_textureData->image.copy(0, 0, width, height);
+ QImage copy = m_textureData->image.copy(0, 0, oldWidth, oldHeight);
+ convert_to_Format_Alpha(&copy);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, copy.constBits());
+ glDeleteTextures(1, &oldTexture);
+ return;
+ }
+
+ if (!m_textureData->fbo)
+ ctx->functions()->glGenFramebuffers(1, &m_textureData->fbo);
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_textureData->fbo);
+
+ GLuint tmp_texture;
+ glGenTextures(1, &tmp_texture);
+ glBindTexture(GL_TEXTURE_2D, tmp_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, tmp_texture, 0);
+
+ ctx->functions()->glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, oldTexture);
+
+ // save current render states
+ GLboolean stencilTestEnabled;
+ GLboolean depthTestEnabled;
+ GLboolean scissorTestEnabled;
+ GLboolean blendEnabled;
+ GLint viewport[4];
+ glGetBooleanv(GL_STENCIL_TEST, &stencilTestEnabled);
+ glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled);
+ glGetBooleanv(GL_SCISSOR_TEST, &scissorTestEnabled);
+ glGetBooleanv(GL_BLEND, &blendEnabled);
+ glGetIntegerv(GL_VIEWPORT, &viewport[0]);
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+
+ glViewport(0, 0, oldWidth, oldHeight);
+
+ if (m_blitProgram == 0) {
+ m_blitProgram = new QGLShaderProgram;
+
+ {
+ QString source;
+ source.append(QLatin1String(qglslMainWithTexCoordsVertexShader));
+ source.append(QLatin1String(qglslUntransformedPositionVertexShader));
+
+ QGLShader *vertexShader = new QGLShader(QGLShader::Vertex, m_blitProgram);
+ vertexShader->compileSourceCode(source);
+
+ m_blitProgram->addShader(vertexShader);
+ }
+
+ {
+ QString source;
+ source.append(QLatin1String(qglslMainFragmentShader));
+ source.append(QLatin1String(qglslImageSrcFragmentShader));
+
+ QGLShader *fragmentShader = new QGLShader(QGLShader::Fragment, m_blitProgram);
+ fragmentShader->compileSourceCode(source);
+
+ m_blitProgram->addShader(fragmentShader);
+ }
+
+ m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+
+ m_blitProgram->link();
+ }
+
+ ctx->functions()->glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_vertexCoordinateArray);
+ ctx->functions()->glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_textureCoordinateArray);
+
+ m_blitProgram->bind();
+ m_blitProgram->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
+ m_blitProgram->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
+ m_blitProgram->disableAttributeArray(int(QT_OPACITY_ATTR));
+ m_blitProgram->setUniformValue("imageTexture", GLuint(0));
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+
+ ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, 0);
+ glDeleteTextures(1, &tmp_texture);
+ glDeleteTextures(1, &oldTexture);
+
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
+
+ // restore render states
+ if (stencilTestEnabled)
+ glEnable(GL_STENCIL_TEST);
+ if (depthTestEnabled)
+ glEnable(GL_DEPTH_TEST);
+ if (scissorTestEnabled)
+ glEnable(GL_SCISSOR_TEST);
+ if (blendEnabled)
+ glEnable(GL_BLEND);
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+}
+
+void QSGDistanceFieldGlyphCache::updateCache()
+{
+ if (m_textureData->pendingGlyphs.isEmpty())
+ return;
+
+ int requiredWidth = m_textureData->currY == 0 ? m_textureData->currX : maxTextureSize();
+ int requiredHeight = qMin(maxTextureSize(), m_textureData->currY + QT_DISTANCEFIELD_TILESIZE);
+
+ resizeTexture((requiredWidth), (requiredHeight));
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ QSet<glyph_t>::const_iterator i = m_textureData->pendingGlyphs.constBegin();
+ for (; i != m_textureData->pendingGlyphs.constEnd(); ++i) {
+ QImage glyph = renderDistanceFieldGlyph(*i);
+ TexCoord c = m_textureData->texCoords.value(*i);
+
+ if (ctx->d_ptr->workaround_brokenFBOReadBack) {
+ QPainter p(&m_textureData->image);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ p.drawImage(c.x, c.y, glyph);
+ p.end();
+ }
+
+ convert_to_Format_Alpha(&glyph);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
+ }
+ m_textureData->pendingGlyphs.clear();
+}
+
+bool QSGDistanceFieldGlyphCache::useWorkaroundBrokenFBOReadback() const
+{
+ return ctx->d_ptr->workaround_brokenFBOReadBack;
+}
+
+bool QSGDistanceFieldGlyphCache::distanceFieldEnabled()
+{
+ return !disableDistanceField();
+}
+
+int QSGDistanceFieldGlyphCache::glyphCount() const
+{
+ return m_glyphCount;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h
new file mode 100644
index 0000000000..5ee439552a
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphcache_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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DISTANCEFIELDGLYPHCACHE_H
+#define DISTANCEFIELDGLYPHCACHE_H
+
+#include <qgl.h>
+#include <qrawfont.h>
+#include <private/qgl_p.h>
+#include <private/qfont_p.h>
+#include <private/qfontengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGLShaderProgram;
+
+class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCache : public QObject
+{
+ Q_OBJECT
+public:
+ ~QSGDistanceFieldGlyphCache();
+
+ static QSGDistanceFieldGlyphCache *get(const QGLContext *ctx, const QRawFont &font);
+
+ struct Metrics {
+ qreal width;
+ qreal height;
+ qreal baselineX;
+ qreal baselineY;
+
+ bool isNull() const { return width == 0 || height == 0; }
+ };
+ Metrics glyphMetrics(glyph_t glyph);
+
+ struct TexCoord {
+ qreal x;
+ qreal y;
+ qreal width;
+ qreal height;
+ qreal xMargin;
+ qreal yMargin;
+
+ TexCoord() : x(0), y(0), width(0), height(0), xMargin(0), yMargin(0) { }
+
+ bool isNull() const { return width == 0 || height == 0; }
+ };
+ TexCoord glyphTexCoord(glyph_t glyph);
+
+ GLuint texture();
+ QSize textureSize() const;
+ int maxTextureSize() const;
+ qreal fontScale() const;
+ int distanceFieldRadius() const;
+ QImage renderDistanceFieldGlyph(glyph_t glyph) const;
+
+ int glyphCount() const;
+
+ void populate(int count, const glyph_t *glyphs);
+ void derefGlyphs(int count, const glyph_t *glyphs);
+ void updateCache();
+
+ bool cacheIsFull() const { return m_textureData->currY >= maxTextureSize(); }
+
+ bool useWorkaroundBrokenFBOReadback() const;
+
+ static bool distanceFieldEnabled();
+
+private Q_SLOTS:
+ void onContextDestroyed(const QGLContext *context);
+
+private:
+ QSGDistanceFieldGlyphCache(const QGLContext *c, const QRawFont &font);
+
+ void createTexture(int width, int height);
+ void resizeTexture(int width, int height);
+
+ static QHash<QPair<const QGLContext *, QFontEngine *>, QSGDistanceFieldGlyphCache *> m_caches;
+
+ QRawFont m_font;
+ QRawFont m_referenceFont;
+
+ int m_glyphCount;
+ QHash<glyph_t, Metrics> m_metrics;
+ mutable int m_maxTextureSize;
+
+ struct DistanceFieldTextureData {
+ GLuint texture;
+ GLuint fbo;
+ QSize size;
+ QHash<glyph_t, TexCoord> texCoords;
+ QSet<glyph_t> pendingGlyphs;
+ QHash<glyph_t, quint32> glyphRefCount;
+ QSet<glyph_t> unusedGlyphs;
+ int currX;
+ int currY;
+ QImage image;
+ bool doubleGlyphResolution;
+
+ DistanceFieldTextureData(const QGLContext *)
+ : texture(0)
+ , fbo(0)
+ , currX(0)
+ , currY(0)
+ , doubleGlyphResolution(false)
+ { }
+ };
+ DistanceFieldTextureData *textureData();
+ DistanceFieldTextureData *m_textureData;
+ static QHash<QFontEngine *, QGLContextGroupResource<DistanceFieldTextureData> > m_textures_data;
+
+ const QGLContext *ctx;
+ QGLShaderProgram *m_blitProgram;
+ GLfloat m_vertexCoordinateArray[8];
+ GLfloat m_textureCoordinateArray[8];
+
+};
+
+QT_END_NAMESPACE
+
+#endif // DISTANCEFIELDGLYPHCACHE_H
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp
new file mode 100644
index 0000000000..ed2dba1ea3
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdistancefieldglyphnode_p.h"
+#include "qsgdistancefieldglyphnode_p_p.h"
+#include "qsgdistancefieldglyphcache_p.h"
+#include <private/qsgcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode()
+ : m_material(0)
+ , m_glyph_cache(0)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
+ , m_style(QSGText::Normal)
+ , m_antialiasingMode(GrayAntialiasing)
+{
+ m_geometry.setDrawingMode(GL_TRIANGLES);
+ setGeometry(&m_geometry);
+
+#ifndef QT_OPENGL_ES
+ setPreferredAntialiasingMode(QSGGlyphNode::SubPixelAntialiasing);
+#endif
+}
+
+QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode()
+{
+ delete m_material;
+ if (m_glyph_cache) {
+ const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
+ m_glyph_cache->derefGlyphs(glyphIndexes.count(), glyphIndexes.constData());
+ }
+}
+
+void QSGDistanceFieldGlyphNode::setColor(const QColor &color)
+{
+ m_color = color;
+ if (m_material != 0) {
+ m_material->setColor(color);
+ setMaterial(m_material); // Indicate the material state has changed
+ }
+}
+
+void QSGDistanceFieldGlyphNode::setPreferredAntialiasingMode(AntialiasingMode mode)
+{
+ if (mode == m_antialiasingMode)
+ return;
+ m_antialiasingMode = mode;
+ updateMaterial();
+}
+
+void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphs &glyphs)
+{
+ QRawFont font = glyphs.font();
+ m_position = QPointF(position.x(), position.y() - font.ascent());
+ m_glyphs = glyphs;
+
+ updateFont();
+ updateGeometry();
+ updateMaterial();
+
+#ifdef QML_RUNTIME_TESTING
+ description = QLatin1String("glyphs");
+#endif
+}
+
+void QSGDistanceFieldGlyphNode::setStyle(QSGText::TextStyle style)
+{
+ m_style = style;
+}
+
+void QSGDistanceFieldGlyphNode::setStyleColor(const QColor &color)
+{
+ m_styleColor = color;
+}
+
+void QSGDistanceFieldGlyphNode::updateGeometry()
+{
+ Q_ASSERT(m_glyph_cache);
+
+ QSGGeometry *g = geometry();
+ QRectF boundingRect;
+
+ const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
+
+ m_glyph_cache->populate(glyphIndexes.count(), glyphIndexes.constData());
+
+ Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT);
+ g->allocate(glyphIndexes.size() * 4, glyphIndexes.size() * 6);
+ QVector4D *vp = (QVector4D *)g->vertexData();
+ ushort *ip = g->indexDataAsUShort();
+
+ QPointF margins(2, 2);
+ QPointF texMargins = margins / m_glyph_cache->fontScale();
+
+ for (int i = 0; i < glyphIndexes.size(); ++i) {
+ quint32 glyphIndex = glyphIndexes.at(i);
+ QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex);
+ QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex);
+
+ if (!metrics.isNull() && !c.isNull()) {
+ metrics.width += margins.x() * 2;
+ metrics.height += margins.y() * 2;
+ metrics.baselineX -= margins.x();
+ metrics.baselineY += margins.y();
+ c.xMargin -= texMargins.x();
+ c.yMargin -= texMargins.y();
+ c.width += texMargins.x() * 2;
+ c.height += texMargins.y() * 2;
+ }
+
+ QPointF glyphPosition = m_glyphs.positions().at(i) + m_position;
+ qreal x = glyphPosition.x() + metrics.baselineX;
+ qreal y = glyphPosition.y() - metrics.baselineY;
+
+ boundingRect |= QRectF(x, y, metrics.width, metrics.height);
+
+ float cx1 = x;
+ float cx2 = x + metrics.width;
+ float cy1 = y;
+ float cy2 = y + metrics.height;
+
+ float tx1 = c.x + c.xMargin;
+ float tx2 = tx1 + c.width;
+ float ty1 = c.y + c.yMargin;
+ float ty2 = ty1 + c.height;
+
+ if (m_baseLine.isNull())
+ m_baseLine = glyphPosition;
+
+ int vi = i & 1 ? (glyphIndexes.size() + 1) / 2 + i / 2 : i / 2;
+ vp[4 * vi + 0] = QVector4D(cx1, cy1, tx1, ty1);
+ vp[4 * vi + 1] = QVector4D(cx2, cy1, tx2, ty1);
+ vp[4 * vi + 2] = QVector4D(cx1, cy2, tx1, ty2);
+ vp[4 * vi + 3] = QVector4D(cx2, cy2, tx2, ty2);
+
+ int o = i * 4;
+ ip[6 * i + 0] = o + 0;
+ ip[6 * i + 1] = o + 2;
+ ip[6 * i + 2] = o + 3;
+ ip[6 * i + 3] = o + 3;
+ ip[6 * i + 4] = o + 1;
+ ip[6 * i + 5] = o + 0;
+ }
+
+ setBoundingRect(boundingRect);
+ markDirty(DirtyGeometry);
+}
+
+void QSGDistanceFieldGlyphNode::updateFont()
+{
+ m_glyph_cache = QSGDistanceFieldGlyphCache::get(QGLContext::currentContext(), m_glyphs.font());
+}
+
+void QSGDistanceFieldGlyphNode::updateMaterial()
+{
+ delete m_material;
+
+ if (m_style == QSGText::Normal) {
+ if (m_antialiasingMode == SubPixelAntialiasing)
+ m_material = new QSGSubPixelDistanceFieldTextMaterial;
+ else
+ m_material = new QSGDistanceFieldTextMaterial;
+ } else {
+ QSGDistanceFieldStyledTextMaterial *material;
+ if (m_style == QSGText::Outline) {
+ material = new QSGDistanceFieldOutlineTextMaterial;
+ } else {
+ QSGDistanceFieldShiftedStyleTextMaterial *sMaterial = new QSGDistanceFieldShiftedStyleTextMaterial;
+ if (m_style == QSGText::Raised)
+ sMaterial->setShift(QPointF(0.0, 1.0));
+ else
+ sMaterial->setShift(QPointF(0.0, -1.0));
+ material = sMaterial;
+ }
+ material->setStyleColor(m_styleColor);
+ m_material = material;
+ }
+
+ m_material->setGlyphCache(m_glyph_cache);
+ m_material->setColor(m_color);
+ setMaterial(m_material);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp
new file mode 100644
index 0000000000..e332434138
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -0,0 +1,656 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdistancefieldglyphnode_p_p.h"
+#include "qsgdistancefieldglyphcache_p.h"
+#include <private/qsgtexture_p.h>
+#include <QtOpenGL/qglfunctions.h>
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGDistanceFieldTextMaterialShader : public QSGMaterialShader
+{
+public:
+ QSGDistanceFieldTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+ virtual char const *const *attributeNames() const;
+
+protected:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ void updateAlphaRange();
+
+ qreal m_fontScale;
+ qreal m_matrixScale;
+
+ int m_matrix_id;
+ int m_textureScale_id;
+ int m_alphaMin_id;
+ int m_alphaMax_id;
+ int m_color_id;
+};
+
+const char *QSGDistanceFieldTextMaterialShader::vertexShader() const {
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *QSGDistanceFieldTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "void main() { \n"
+ " gl_FragColor = color * smoothstep(alphaMin, \n"
+ " alphaMax, \n"
+ " texture2D(texture, sampleCoord).a); \n"
+ "}";
+}
+
+char const *const *QSGDistanceFieldTextMaterialShader::attributeNames() const {
+ static char const *const attr[] = { "vCoord", "tCoord", 0 };
+ return attr;
+}
+
+QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader()
+ : m_fontScale(1.0)
+ , m_matrixScale(1.0)
+{
+}
+
+void QSGDistanceFieldTextMaterialShader::updateAlphaRange()
+{
+ qreal combinedScale = m_fontScale * m_matrixScale;
+ qreal alphaMin = qMax(0.0, 0.5 - 0.07 / combinedScale);
+ qreal alphaMax = qMin(0.5 + 0.07 / combinedScale, 1.0);
+ m_program.setUniformValue(m_alphaMin_id, GLfloat(alphaMin));
+ m_program.setUniformValue(m_alphaMax_id, GLfloat(alphaMax));
+}
+
+void QSGDistanceFieldTextMaterialShader::initialize()
+{
+ QSGMaterialShader::initialize();
+ m_matrix_id = m_program.uniformLocation("matrix");
+ m_textureScale_id = m_program.uniformLocation("textureScale");
+ m_color_id = m_program.uniformLocation("color");
+ m_alphaMin_id = m_program.uniformLocation("alphaMin");
+ m_alphaMax_id = m_program.uniformLocation("alphaMax");
+}
+
+void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect);
+ QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
+
+ bool updated = material->updateTexture();
+ if (updated && !material->glyphCache()->useWorkaroundBrokenFBOReadback())
+ activate();
+
+ if (oldMaterial == 0
+ || material->color() != oldMaterial->color()
+ || state.isOpacityDirty()) {
+ QVector4D color(material->color().redF(), material->color().greenF(),
+ material->color().blueF(), material->color().alphaF());
+ color *= state.opacity();
+ m_program.setUniformValue(m_color_id, color);
+ }
+
+ bool updateRange = false;
+ if (oldMaterial == 0
+ || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale()) {
+ m_fontScale = material->glyphCache()->fontScale();
+ updateRange = true;
+ }
+ if (state.isMatrixDirty()) {
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+ m_matrixScale = qSqrt(state.modelViewMatrix().determinant());
+ updateRange = true;
+ }
+ if (updateRange)
+ updateAlphaRange();
+
+ Q_ASSERT(material->glyphCache());
+
+ if (updated
+ || oldMaterial == 0
+ || oldMaterial->glyphCache()->texture() != material->glyphCache()->texture()) {
+ m_program.setUniformValue(m_textureScale_id, QVector2D(1.0 / material->glyphCache()->textureSize().width(),
+ 1.0 / material->glyphCache()->textureSize().height()));
+ glBindTexture(GL_TEXTURE_2D, material->glyphCache()->texture());
+
+ if (updated) {
+ // Set the mag/min filters to be linear. We only need to do this when the texture
+ // has been recreated.
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ }
+ }
+}
+
+QSGDistanceFieldTextMaterial::QSGDistanceFieldTextMaterial()
+ : m_glyph_cache(0)
+{
+ setFlag(Blending, true);
+}
+
+QSGDistanceFieldTextMaterial::~QSGDistanceFieldTextMaterial()
+{
+}
+
+QSGMaterialType *QSGDistanceFieldTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader() const
+{
+ return new QSGDistanceFieldTextMaterialShader;
+}
+
+bool QSGDistanceFieldTextMaterial::updateTexture()
+{
+ m_glyph_cache->updateCache();
+ QSize glyphCacheSize = m_glyph_cache->textureSize();
+ if (glyphCacheSize != m_size) {
+ m_size = glyphCacheSize;
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int QSGDistanceFieldTextMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGDistanceFieldTextMaterial *other = static_cast<const QSGDistanceFieldTextMaterial *>(o);
+ if (m_glyph_cache->fontScale() != other->m_glyph_cache->fontScale()) {
+ qreal s1 = m_glyph_cache->fontScale();
+ qreal s2 = other->m_glyph_cache->fontScale();
+ return int(s2 < s1) - int(s1 < s2);
+ }
+ QRgb c1 = m_color.rgba();
+ QRgb c2 = other->m_color.rgba();
+ return int(c2 < c1) - int(c1 < c2);
+}
+
+
+class DistanceFieldStyledTextMaterialShader : public QSGDistanceFieldTextMaterialShader
+{
+public:
+ DistanceFieldStyledTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual void initialize();
+ virtual const char *fragmentShader() const = 0;
+
+ int m_styleColor_id;
+};
+
+DistanceFieldStyledTextMaterialShader::DistanceFieldStyledTextMaterialShader()
+ : QSGDistanceFieldTextMaterialShader()
+{
+}
+
+void DistanceFieldStyledTextMaterialShader::initialize()
+{
+ QSGDistanceFieldTextMaterialShader::initialize();
+ m_styleColor_id = m_program.uniformLocation("styleColor");
+}
+
+void DistanceFieldStyledTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ QSGDistanceFieldTextMaterialShader::updateState(state, newEffect, oldEffect);
+
+ QSGDistanceFieldStyledTextMaterial *material = static_cast<QSGDistanceFieldStyledTextMaterial *>(newEffect);
+ QSGDistanceFieldStyledTextMaterial *oldMaterial = static_cast<QSGDistanceFieldStyledTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0
+ || material->styleColor() != oldMaterial->styleColor()
+ || (state.isOpacityDirty())) {
+ QVector4D color(material->styleColor().redF(), material->styleColor().greenF(),
+ material->styleColor().blueF(), material->styleColor().alphaF());
+ color *= state.opacity();
+ m_program.setUniformValue(m_styleColor_id, color);
+ }
+}
+
+QSGDistanceFieldStyledTextMaterial::QSGDistanceFieldStyledTextMaterial()
+ : QSGDistanceFieldTextMaterial()
+{
+}
+
+QSGDistanceFieldStyledTextMaterial::~QSGDistanceFieldStyledTextMaterial()
+{
+}
+
+int QSGDistanceFieldStyledTextMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGDistanceFieldStyledTextMaterial *other = static_cast<const QSGDistanceFieldStyledTextMaterial *>(o);
+ if (m_styleColor != other->m_styleColor) {
+ QRgb c1 = m_styleColor.rgba();
+ QRgb c2 = other->m_styleColor.rgba();
+ return int(c2 < c1) - int(c1 < c2);
+ }
+ return QSGDistanceFieldTextMaterial::compare(o);
+}
+
+
+class DistanceFieldOutlineTextMaterialShader : public DistanceFieldStyledTextMaterialShader
+{
+public:
+ DistanceFieldOutlineTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual void initialize();
+ virtual const char *fragmentShader() const;
+
+ void updateOutlineAlphaRange(int dfRadius);
+
+ int m_outlineAlphaMax0_id;
+ int m_outlineAlphaMax1_id;
+};
+
+const char *DistanceFieldOutlineTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform lowp vec4 styleColor; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "uniform highp float outlineAlphaMax0; \n"
+ "uniform highp float outlineAlphaMax1; \n"
+ "void main() { \n"
+ " mediump float d = texture2D(texture, sampleCoord).a; \n"
+ " gl_FragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d)) \n"
+ " * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d); \n"
+ "}";
+}
+
+DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader()
+ : DistanceFieldStyledTextMaterialShader()
+{
+}
+
+void DistanceFieldOutlineTextMaterialShader::initialize()
+{
+ DistanceFieldStyledTextMaterialShader::initialize();
+ m_outlineAlphaMax0_id = m_program.uniformLocation("outlineAlphaMax0");
+ m_outlineAlphaMax1_id = m_program.uniformLocation("outlineAlphaMax1");
+}
+
+void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(int dfRadius)
+{
+ qreal outlineLimit = qMax(qreal(0.2), qreal(0.5 - 0.5 / dfRadius / m_fontScale));
+
+ qreal combinedScale = m_fontScale * m_matrixScale;
+ qreal alphaMin = qMax(0.0, 0.5 - 0.07 / combinedScale);
+ qreal styleAlphaMin0 = qMax(0.0, outlineLimit - 0.07 / combinedScale);
+ qreal styleAlphaMin1 = qMin(qreal(outlineLimit + 0.07 / combinedScale), alphaMin);
+ m_program.setUniformValue(m_outlineAlphaMax0_id, GLfloat(styleAlphaMin0));
+ m_program.setUniformValue(m_outlineAlphaMax1_id, GLfloat(styleAlphaMin1));
+}
+
+void DistanceFieldOutlineTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ DistanceFieldStyledTextMaterialShader::updateState(state, newEffect, oldEffect);
+
+ QSGDistanceFieldOutlineTextMaterial *material = static_cast<QSGDistanceFieldOutlineTextMaterial *>(newEffect);
+ QSGDistanceFieldOutlineTextMaterial *oldMaterial = static_cast<QSGDistanceFieldOutlineTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0
+ || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale()
+ || state.isMatrixDirty())
+ updateOutlineAlphaRange(material->glyphCache()->distanceFieldRadius());
+}
+
+
+QSGDistanceFieldOutlineTextMaterial::QSGDistanceFieldOutlineTextMaterial()
+ : QSGDistanceFieldStyledTextMaterial()
+{
+}
+
+QSGDistanceFieldOutlineTextMaterial::~QSGDistanceFieldOutlineTextMaterial()
+{
+}
+
+QSGMaterialType *QSGDistanceFieldOutlineTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGDistanceFieldOutlineTextMaterial::createShader() const
+{
+ return new DistanceFieldOutlineTextMaterialShader;
+}
+
+
+class DistanceFieldShiftedStyleTextMaterialShader : public DistanceFieldStyledTextMaterialShader
+{
+public:
+ DistanceFieldShiftedStyleTextMaterialShader();
+
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual void initialize();
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+ void updateShift(const QSGDistanceFieldGlyphCache *cache, const QPointF& shift);
+
+ int m_shift_id;
+};
+
+DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader()
+ : DistanceFieldStyledTextMaterialShader()
+{
+}
+
+void DistanceFieldShiftedStyleTextMaterialShader::initialize()
+{
+ DistanceFieldStyledTextMaterialShader::initialize();
+ m_shift_id = m_program.uniformLocation("shift");
+}
+
+void DistanceFieldShiftedStyleTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ DistanceFieldStyledTextMaterialShader::updateState(state, newEffect, oldEffect);
+
+ QSGDistanceFieldShiftedStyleTextMaterial *material = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(newEffect);
+ QSGDistanceFieldShiftedStyleTextMaterial *oldMaterial = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0
+ || oldMaterial->glyphCache()->fontScale() != material->glyphCache()->fontScale()
+ || oldMaterial->shift() != material->shift()
+ || oldMaterial->glyphCache()->textureSize() != material->glyphCache()->textureSize()) {
+ updateShift(material->glyphCache(), material->shift());
+ }
+}
+
+void DistanceFieldShiftedStyleTextMaterialShader::updateShift(const QSGDistanceFieldGlyphCache *cache, const QPointF &shift)
+{
+ QPointF texel(1.0 / cache->fontScale() * shift.x(),
+ 1.0 / cache->fontScale() * shift.y());
+ m_program.setUniformValue(m_shift_id, texel);
+}
+
+const char *DistanceFieldShiftedStyleTextMaterialShader::vertexShader() const
+{
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "uniform highp vec2 shift; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec2 shiftedSampleCoord; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " shiftedSampleCoord = (tCoord - shift) * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}";
+}
+
+const char *DistanceFieldShiftedStyleTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec2 shiftedSampleCoord; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform lowp vec4 styleColor; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "void main() { \n"
+ " highp float a = smoothstep(alphaMin, alphaMax, texture2D(texture, sampleCoord).a);\n"
+ " highp vec4 shifted = styleColor * smoothstep(alphaMin, \n"
+ " alphaMax, \n"
+ " texture2D(texture, shiftedSampleCoord).a); \n"
+ " gl_FragColor = mix(shifted, color, a); \n"
+ "}";
+}
+
+QSGDistanceFieldShiftedStyleTextMaterial::QSGDistanceFieldShiftedStyleTextMaterial()
+ : QSGDistanceFieldStyledTextMaterial()
+{
+}
+
+QSGDistanceFieldShiftedStyleTextMaterial::~QSGDistanceFieldShiftedStyleTextMaterial()
+{
+}
+
+QSGMaterialType *QSGDistanceFieldShiftedStyleTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGDistanceFieldShiftedStyleTextMaterial::createShader() const
+{
+ return new DistanceFieldShiftedStyleTextMaterialShader;
+}
+
+
+class QSGSubPixelDistanceFieldTextMaterialShader : public QSGDistanceFieldTextMaterialShader
+{
+public:
+ virtual void initialize();
+ virtual void activate();
+ virtual void deactivate();
+ virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
+
+protected:
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
+
+private:
+ int m_fontScale_id;
+ int m_vecDelta_id;
+};
+
+const char *QSGSubPixelDistanceFieldTextMaterialShader::vertexShader() const {
+ return
+ "uniform highp mat4 matrix; \n"
+ "uniform highp vec2 textureScale; \n"
+ "uniform highp float fontScale; \n"
+ "uniform highp vec4 vecDelta; \n"
+ "attribute highp vec4 vCoord; \n"
+ "attribute highp vec2 tCoord; \n"
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec3 sampleFarLeft; \n"
+ "varying highp vec3 sampleNearLeft; \n"
+ "varying highp vec3 sampleNearRight; \n"
+ "varying highp vec3 sampleFarRight; \n"
+ "void main() { \n"
+ " sampleCoord = tCoord * textureScale; \n"
+ " gl_Position = matrix * vCoord; \n"
+ // Calculate neighbour pixel position in item space.
+ " highp vec3 wDelta = gl_Position.w * vecDelta.xyw; \n"
+ " highp vec3 farLeft = vCoord.xyw - 0.667 * wDelta; \n"
+ " highp vec3 nearLeft = vCoord.xyw - 0.333 * wDelta; \n"
+ " highp vec3 nearRight = vCoord.xyw + 0.333 * wDelta; \n"
+ " highp vec3 farRight = vCoord.xyw + 0.667 * wDelta; \n"
+ // Calculate neighbour texture coordinate.
+ " highp vec2 scale = textureScale / fontScale; \n"
+ " highp vec2 base = sampleCoord - scale * vCoord.xy; \n"
+ " sampleFarLeft = vec3(base * farLeft.z + scale * farLeft.xy, farLeft.z); \n"
+ " sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z); \n"
+ " sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z); \n"
+ " sampleFarRight = vec3(base * farRight.z + scale * farRight.xy, farRight.z); \n"
+ "}";
+}
+
+const char *QSGSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
+ return
+ "varying highp vec2 sampleCoord; \n"
+ "varying highp vec3 sampleFarLeft; \n"
+ "varying highp vec3 sampleNearLeft; \n"
+ "varying highp vec3 sampleNearRight; \n"
+ "varying highp vec3 sampleFarRight; \n"
+ "uniform sampler2D texture; \n"
+ "uniform lowp vec4 color; \n"
+ "uniform highp float alphaMin; \n"
+ "uniform highp float alphaMax; \n"
+ "void main() { \n"
+ " highp vec4 n; \n"
+ " n.x = texture2DProj(texture, sampleFarLeft).a; \n"
+ " n.y = texture2DProj(texture, sampleNearLeft).a; \n"
+ " highp float c = texture2D(texture, sampleCoord).a; \n"
+ " n.z = texture2DProj(texture, sampleNearRight).a; \n"
+ " n.w = texture2DProj(texture, sampleFarRight).a; \n"
+#if 0
+ // Blurrier, faster.
+ " n = smoothstep(alphaMin, alphaMax, n); \n"
+ " c = smoothstep(alphaMin, alphaMax, c); \n"
+#else
+ // Sharper, slower.
+ " highp vec2 d = min(abs(n.yw - n.xz) * 2., 0.67); \n"
+ " highp vec2 lo = mix(vec2(alphaMin), vec2(0.5), d); \n"
+ " highp vec2 hi = mix(vec2(alphaMax), vec2(0.5), d); \n"
+ " n = smoothstep(lo.xxyy, hi.xxyy, n); \n"
+ " c = smoothstep(lo.x + lo.y, hi.x + hi.y, 2. * c); \n"
+#endif
+ " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
+ "}";
+}
+
+//const char *QSGSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
+// return
+// "#extension GL_OES_standard_derivatives: enable \n"
+// "varying highp vec2 sampleCoord; \n"
+// "uniform sampler2D texture; \n"
+// "uniform lowp vec4 color; \n"
+// "uniform highp float alphaMin; \n"
+// "uniform highp float alphaMax; \n"
+// "void main() { \n"
+// " highp vec2 delta = dFdx(sampleCoord); \n"
+// " highp vec4 n; \n"
+// " n.x = texture2D(texture, sampleCoord - 0.667 * delta).a; \n"
+// " n.y = texture2D(texture, sampleCoord - 0.333 * delta).a; \n"
+// " highp float c = texture2D(texture, sampleCoord).a; \n"
+// " n.z = texture2D(texture, sampleCoord + 0.333 * delta).a; \n"
+// " n.w = texture2D(texture, sampleCoord + 0.667 * delta).a; \n"
+// " n = smoothstep(alphaMin, alphaMax, n); \n"
+// " c = smoothstep(alphaMin, alphaMax, c); \n"
+// " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
+// "}";
+//}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::initialize()
+{
+ QSGDistanceFieldTextMaterialShader::initialize();
+ m_fontScale_id = m_program.uniformLocation("fontScale");
+ m_vecDelta_id = m_program.uniformLocation("vecDelta");
+}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::activate()
+{
+ QSGDistanceFieldTextMaterialShader::activate();
+ glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR);
+}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::deactivate()
+{
+ QSGDistanceFieldTextMaterialShader::deactivate();
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+void QSGSubPixelDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect);
+ QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
+
+ if (oldMaterial == 0 || material->color() != oldMaterial->color()) {
+ QColor c = material->color();
+ state.context()->functions()->glBlendColor(c.redF(), c.greenF(), c.blueF(), 1.0f);
+ }
+
+ if (oldMaterial == 0 || material->glyphCache()->fontScale() != oldMaterial->glyphCache()->fontScale())
+ m_program.setUniformValue(m_fontScale_id, GLfloat(material->glyphCache()->fontScale()));
+
+ if (oldMaterial == 0 || state.isMatrixDirty()) {
+ int viewportWidth = state.viewportRect().width();
+ QMatrix4x4 mat = state.combinedMatrix().inverted();
+ m_program.setUniformValue(m_vecDelta_id, mat.column(0) * (qreal(2) / viewportWidth));
+ }
+
+ QSGDistanceFieldTextMaterialShader::updateState(state, newEffect, oldEffect);
+}
+
+QSGMaterialType *QSGSubPixelDistanceFieldTextMaterial::type() const
+{
+ static QSGMaterialType type;
+ return &type;
+}
+
+QSGMaterialShader *QSGSubPixelDistanceFieldTextMaterial::createShader() const
+{
+ return new QSGSubPixelDistanceFieldTextMaterialShader;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h
new file mode 100644
index 0000000000..d42f187af3
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DISTANCEFIELD_GLYPHNODE_H
+#define DISTANCEFIELD_GLYPHNODE_H
+
+#include <private/qsgadaptationlayer_p.h>
+#include "qsgtexture.h"
+#include <qsgtext_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGDistanceFieldGlyphCache;
+class QSGDistanceFieldTextMaterial;
+class QSGDistanceFieldGlyphNode: public QSGGlyphNode
+{
+public:
+ QSGDistanceFieldGlyphNode();
+ ~QSGDistanceFieldGlyphNode();
+
+ virtual QPointF baseLine() const { return m_baseLine; }
+ virtual void setGlyphs(const QPointF &position, const QGlyphs &glyphs);
+ virtual void setColor(const QColor &color);
+
+ virtual void setPreferredAntialiasingMode(AntialiasingMode mode);
+
+ void setStyle(QSGText::TextStyle style);
+ void setStyleColor(const QColor &color);
+
+private:
+ void updateGeometry();
+ void updateFont();
+ void updateMaterial();
+
+ QColor m_color;
+ QPointF m_baseLine;
+ QSGDistanceFieldTextMaterial *m_material;
+ QPointF m_position;
+ QGlyphs m_glyphs;
+ QSGDistanceFieldGlyphCache *m_glyph_cache;
+ QSGGeometry m_geometry;
+ QSGText::TextStyle m_style;
+ QColor m_styleColor;
+ AntialiasingMode m_antialiasingMode;
+};
+
+QT_END_HEADER
+
+QT_END_NAMESPACE
+
+#endif // DISTANCEFIELD_GLYPHNODE_H
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h
new file mode 100644
index 0000000000..37415e5dae
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DISTANCEFIELDTEXTMATERIAL_H
+#define DISTANCEFIELDTEXTMATERIAL_H
+
+#include <qsgmaterial.h>
+#include "qsgdistancefieldglyphnode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGDistanceFieldGlyphCache;
+
+class QSGDistanceFieldTextMaterial: public QSGMaterial
+{
+public:
+ QSGDistanceFieldTextMaterial();
+ ~QSGDistanceFieldTextMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setColor(const QColor &color) { m_color = color; }
+ const QColor &color() const { return m_color; }
+
+ void setGlyphCache(QSGDistanceFieldGlyphCache *a) { m_glyph_cache = a; }
+ QSGDistanceFieldGlyphCache *glyphCache() const { return m_glyph_cache; }
+
+ bool updateTexture();
+
+protected:
+ QSize m_size;
+ QColor m_color;
+ QSGDistanceFieldGlyphCache *m_glyph_cache;
+};
+
+class QSGDistanceFieldStyledTextMaterial : public QSGDistanceFieldTextMaterial
+{
+public:
+ QSGDistanceFieldStyledTextMaterial();
+ ~QSGDistanceFieldStyledTextMaterial();
+
+ virtual QSGMaterialType *type() const = 0;
+ virtual QSGMaterialShader *createShader() const = 0;
+ virtual int compare(const QSGMaterial *other) const;
+
+ void setStyleColor(const QColor &color) { m_styleColor = color; }
+ const QColor &styleColor() const { return m_styleColor; }
+
+protected:
+ QColor m_styleColor;
+};
+
+class QSGDistanceFieldOutlineTextMaterial : public QSGDistanceFieldStyledTextMaterial
+{
+public:
+ QSGDistanceFieldOutlineTextMaterial();
+ ~QSGDistanceFieldOutlineTextMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+};
+
+class QSGDistanceFieldShiftedStyleTextMaterial : public QSGDistanceFieldStyledTextMaterial
+{
+public:
+ QSGDistanceFieldShiftedStyleTextMaterial();
+ ~QSGDistanceFieldShiftedStyleTextMaterial();
+
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+
+ void setShift(const QPointF &shift) { m_shift = shift; }
+ const QPointF &shift() const { return m_shift; }
+
+protected:
+ QPointF m_shift;
+};
+
+class QSGSubPixelDistanceFieldTextMaterial : public QSGDistanceFieldTextMaterial
+{
+public:
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // DISTANCEFIELDTEXTMATERIAL_H
diff --git a/src/declarative/scenegraph/qsgflashnode.cpp b/src/declarative/scenegraph/qsgflashnode.cpp
new file mode 100644
index 0000000000..c2c1919f82
--- /dev/null
+++ b/src/declarative/scenegraph/qsgflashnode.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**Ëš
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgflashnode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QSGFlashNode::QSGFlashNode()
+ : m_counter(1)
+{
+ setFlag(UsePreprocess);
+ setColor(QColor(rand()%56 + 200, rand()%56 + 200, rand()%156 + 100)); // A random, mostly yellow, color
+}
+
+void QSGFlashNode::preprocess()
+{
+ if (m_counter) {
+ --m_counter;
+ } else {
+ delete this;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgflashnode_p.h b/src/declarative/scenegraph/qsgflashnode_p.h
new file mode 100644
index 0000000000..776ae48f13
--- /dev/null
+++ b/src/declarative/scenegraph/qsgflashnode_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**Ëš
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGFLASHNODE_H
+#define QSGFLASHNODE_H
+
+#include <QSGSimpleRectNode>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGFlashNode : public QSGSimpleRectNode
+{
+public:
+ QSGFlashNode();
+
+ void preprocess();
+
+private:
+ int m_counter;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGFLASHNODE_H
+
diff --git a/src/declarative/scenegraph/scenegraph.pri b/src/declarative/scenegraph/scenegraph.pri
new file mode 100644
index 0000000000..77a93e4811
--- /dev/null
+++ b/src/declarative/scenegraph/scenegraph.pri
@@ -0,0 +1,80 @@
+INCLUDEPATH += $$PWD/coreapi $$PWD/convenience $$PWD/3d
+!contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL
+
+QT += opengl
+
+
+# Core API
+HEADERS += \
+ $$PWD/coreapi/qsgdefaultrenderer_p.h \
+ $$PWD/coreapi/qsggeometry.h \
+ $$PWD/coreapi/qsgmaterial.h \
+ $$PWD/coreapi/qsgmatrix4x4stack.h \
+ $$PWD/coreapi/qsgmatrix4x4stack_p.h \
+ $$PWD/coreapi/qsgnode.h \
+ $$PWD/coreapi/qsgnodeupdater_p.h \
+ $$PWD/coreapi/qsgrenderer_p.h
+SOURCES += \
+ $$PWD/coreapi/qsgdefaultrenderer.cpp \
+ $$PWD/coreapi/qsggeometry.cpp \
+ $$PWD/coreapi/qsgmaterial.cpp \
+ $$PWD/coreapi/qsgmatrix4x4stack.cpp \
+ $$PWD/coreapi/qsgnode.cpp \
+ $$PWD/coreapi/qsgnodeupdater.cpp \
+ $$PWD/coreapi/qsgrenderer.cpp
+
+
+# Util API
+HEADERS += \
+ $$PWD/util/qsgareaallocator_p.h \
+ $$PWD/util/qsgengine.h \
+ $$PWD/util/qsgflatcolormaterial.h \
+ $$PWD/util/qsgsimplerectnode.h \
+ $$PWD/util/qsgsimpletexturenode.h \
+ $$PWD/util/qsgtexturematerial.h \
+ $$PWD/util/qsgtexturematerial_p.h \
+ $$PWD/util/qsgvertexcolormaterial_p.h \
+ $$PWD/util/qsgtexture.h \
+ $$PWD/util/qsgtexture_p.h \
+ $$PWD/util/qsgtextureprovider_p.h \
+ $$PWD/util/qsgpainternode_p.h
+
+SOURCES += \
+ $$PWD/util/qsgareaallocator.cpp \
+ $$PWD/util/qsgengine.cpp \
+ $$PWD/util/qsgflatcolormaterial.cpp \
+ $$PWD/util/qsgsimplerectnode.cpp \
+ $$PWD/util/qsgsimpletexturenode.cpp \
+ $$PWD/util/qsgtexturematerial.cpp \
+ $$PWD/util/qsgvertexcolormaterial.cpp \
+ $$PWD/util/qsgtexture.cpp \
+ $$PWD/util/qsgtextureprovider.cpp \
+ $$PWD/util/qsgpainternode.cpp
+
+
+# QML / Adaptations API
+HEADERS += \
+ $$PWD/qsgadaptationlayer_p.h \
+ $$PWD/qsgcontext_p.h \
+ $$PWD/qsgcontextplugin_p.h \
+ $$PWD/qsgdefaultglyphnode_p.h \
+ $$PWD/qsgdistancefieldglyphcache_p.h \
+ $$PWD/qsgdistancefieldglyphnode_p.h \
+ $$PWD/qsgdistancefieldglyphnode_p_p.h \
+ $$PWD/qsgdefaultglyphnode_p_p.h \
+ $$PWD/qsgdefaultimagenode_p.h \
+ $$PWD/qsgdefaultrectanglenode_p.h \
+ $$PWD/qsgflashnode_p.h
+
+SOURCES += \
+ $$PWD/qsgadaptationlayer.cpp \
+ $$PWD/qsgcontext.cpp \
+ $$PWD/qsgcontextplugin.cpp \
+ $$PWD/qsgdefaultglyphnode.cpp \
+ $$PWD/qsgdefaultglyphnode_p.cpp \
+ $$PWD/qsgdistancefieldglyphcache.cpp \
+ $$PWD/qsgdistancefieldglyphnode.cpp \
+ $$PWD/qsgdistancefieldglyphnode_p.cpp \
+ $$PWD/qsgdefaultimagenode.cpp \
+ $$PWD/qsgdefaultrectanglenode.cpp \
+ $$PWD/qsgflashnode.cpp
diff --git a/src/declarative/scenegraph/util/qsgareaallocator.cpp b/src/declarative/scenegraph/util/qsgareaallocator.cpp
new file mode 100644
index 0000000000..a28575c982
--- /dev/null
+++ b/src/declarative/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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 &currentRect, 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/declarative/scenegraph/util/qsgareaallocator_p.h b/src/declarative/scenegraph/util/qsgareaallocator_p.h
new file mode 100644
index 0000000000..f84732fbdb
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgareaallocator_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef AREAALLOCATOR_H
+#define AREAALLOCATOR_H
+
+#include <QtCore/qsize.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRect;
+class QPoint;
+struct QSGAreaAllocatorNode;
+class Q_DECLARATIVE_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 &currentRect, 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/declarative/scenegraph/util/qsgengine.cpp b/src/declarative/scenegraph/util/qsgengine.cpp
new file mode 100644
index 0000000000..1b7f05809b
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgengine.cpp
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgengine.h"
+
+#include <private/qsgtexture_p.h>
+#include <private/qsgrenderer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSGEnginePrivate : public QObjectPrivate
+{
+public:
+ QSGEnginePrivate()
+ : context(0)
+ , clearBeforeRender(true)
+ {
+ }
+
+ QSGContext *context;
+
+ bool clearBeforeRender;
+};
+
+
+/*!
+ \class QSGEngine
+ \brief The QSGEngine class serves as a generic entry point into scene graph specific APIs.
+
+ The QSGEngine class provides factory functions for creating textures. Though the user
+ can implement any type of texture using the abstract QSGTexture class, the QSGEngine
+ class provides some convenience for the default usecases. This also allows the scene
+ graph to apply hardware specific optimzations.
+
+ */
+
+
+
+/*!
+ Constructs a new QSGengine
+ */
+QSGEngine::QSGEngine(QObject *parent) :
+ QObject(*(new QSGEnginePrivate), parent)
+{
+}
+
+
+QSGEngine::~QSGEngine()
+{
+}
+
+/*!
+ \enum TextureOption
+
+ The TextureOption enums are used to customize a texture is wrapped.
+
+ \value TextureHasAlphaChannel The texture has an alpha channel and should
+ be drawn using blending.
+
+ \value TextureHasMipmaps The texture has mipmaps and can be drawn with
+ mipmapping enabled.
+
+ \value TextureOwnsGLTexture The texture object owns the texture id and
+ will delete the GL texture when the texture object is deleted.
+
+ */
+
+/*!
+ \fn void QSGEngine::beforeRendering()
+
+ This signal is emitted before the scene starts rendering.
+
+ Combined with the modes for clearing the background, this option
+ can be used to paint using raw GL under QML content.
+
+ The GL context used for rendering the scene graph will be bound
+ at this point.
+*/
+
+/*!
+ \fn void QSGEngine::afterRendering()
+
+ This signal is emitted after the scene has completed rendering, before swapbuffers is called.
+
+ This signal can be used to paint using raw GL on top of QML content,
+ or to do screen scraping of the current frame buffer.
+
+ The GL context used for rendering the scene graph will be bound at this point.
+ */
+
+
+
+/*!
+ Sets weither the scene graph rendering of QML should clear the color buffer
+ before it starts rendering to \a enbled.
+
+ By disabling clearing of the color buffer, it is possible to do GL painting
+ under the scene graph.
+
+ The color buffer is cleared by default.
+ */
+
+void QSGEngine::setClearBeforeRendering(bool enabled)
+{
+ Q_D(QSGEngine);
+ d->clearBeforeRender = enabled;
+ if (d->clearBeforeRender) {
+ d->context->renderer()->setClearMode(QSGRenderer::ClearDepthBuffer
+ | QSGRenderer::ClearColorBuffer);
+ } else {
+ d->context->renderer()->setClearMode(QSGRenderer::ClearDepthBuffer);
+ }
+}
+
+
+
+/*!
+ Returns weither clearing of the color buffer is done before rendering or not.
+ */
+
+bool QSGEngine::clearBeforeRendering() const
+{
+ Q_D(const QSGEngine);
+ return d->clearBeforeRender;
+}
+
+
+
+/*!
+ Creates a new QSGTexture from the supplied \a image. If the image has an
+ alpha channel, the corresponding texture will have an alpha channel.
+
+ The caller of the function is responsible for deleting the returned texture.
+
+ The actual GL texture will be deleted when the texture object is deleted.
+ */
+
+QSGTexture *QSGEngine::createTextureFromImage(const QImage &image) const
+{
+ Q_D(const QSGEngine);
+ return d->context->createTexture(image);
+}
+
+
+
+/*!
+ Creates a new QSGTexture object from an existing GL texture \a id.
+
+ The caller of the function is responsible for deleting the returned texture.
+
+ Use \a options to customize the texture attributes.
+ */
+QSGTexture *QSGEngine::createTextureFromId(uint id, const QSize &size, TextureOptions options) const
+{
+ QSGPlainTexture *texture = new QSGPlainTexture();
+ texture->setTextureId(id);
+ texture->setHasAlphaChannel(options & TextureHasAlphaChannel);
+ texture->setHasMipmaps(options & TextureHasMipmaps);
+ texture->setOwnsTexture(options & TextureOwnsGLTexture);
+ texture->setTextureSize(size);
+ return texture;
+}
+
+
+
+/*!
+ \internal
+
+ Sets the scene graph context of this engine to context.
+
+ The context will be set by the QSGcontext::initialize() function,
+ as part of constructing the engine object.
+ */
+
+void QSGEngine::setContext(QSGContext *context)
+{
+ Q_D(QSGEngine);
+ d->context = context;
+}
+
+
+
+/*!
+ Sets the background color of the scene graph to \a color.
+
+ Changing the clear color has no effect when clearing before rendering is
+ disabled.
+ */
+
+void QSGEngine::setClearColor(const QColor &color)
+{
+ d_func()->context->renderer()->setClearColor(color);
+}
+
+
+
+/*!
+ Returns the background color of the scene graph
+ */
+
+QColor QSGEngine::clearColor() const
+{
+ return d_func()->context->renderer()->clearColor();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgengine.h b/src/declarative/scenegraph/util/qsgengine.h
new file mode 100644
index 0000000000..9e07f3530d
--- /dev/null
+++ b/src/declarative/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGENGINE_H
+#define QSGENGINE_H
+
+#include <QObject>
+
+#include <qsgtexture.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGEnginePrivate;
+
+class QSGContext;
+class Q_DECLARATIVE_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;
+
+signals:
+ void beforeRendering();
+ void afterRendering();
+
+private:
+ QSGEngine(QObject *parent = 0);
+ ~QSGEngine();
+
+ friend class QSGContext;
+ friend class QSGContextPrivate;
+ void setContext(QSGContext *context);
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGENGINE_H
diff --git a/src/declarative/scenegraph/util/qsgflatcolormaterial.cpp b/src/declarative/scenegraph/util/qsgflatcolormaterial.cpp
new file mode 100644
index 0000000000..e348655e6b
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgflatcolormaterial.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgflatcolormaterial.h"
+
+#include <qglshaderprogram.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);
+ m_program.setUniformValue(m_color_id, v);
+ }
+
+ if (state.isMatrixDirty())
+ m_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 = m_program.uniformLocation("matrix");
+ m_color_id = m_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"
+ "}";
+}
+
+
+QSGFlatColorMaterial::QSGFlatColorMaterial() : m_color(QColor(255, 255, 255))
+{
+}
+
+void QSGFlatColorMaterial::setColor(const QColor &color)
+{
+ m_color = color;
+ setFlag(Blending, m_color.alpha() != 0xff);
+}
+
+
+QSGMaterialType *QSGFlatColorMaterial::type() const
+{
+ return &FlatColorMaterialShader::type;
+}
+
+QSGMaterialShader *QSGFlatColorMaterial::createShader() const
+{
+ return new FlatColorMaterialShader;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgflatcolormaterial.h b/src/declarative/scenegraph/util/qsgflatcolormaterial.h
new file mode 100644
index 0000000000..d9a8d5973c
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgflatcolormaterial.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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FLATCOLORMATERIAL_H
+#define FLATCOLORMATERIAL_H
+
+#include <qsgmaterial.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_AUTOTEST_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; }
+
+private:
+ QColor m_color;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // FLATCOLORMATERIAL_H
diff --git a/src/declarative/scenegraph/util/qsgpainternode.cpp b/src/declarative/scenegraph/util/qsgpainternode.cpp
new file mode 100644
index 0000000000..569f1be19e
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgpainternode.cpp
@@ -0,0 +1,373 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpainternode_p.h"
+
+#include "qsgpainteditem.h"
+#include <private/qsgcontext_p.h>
+#include <qglframebufferobject.h>
+#include <qglfunctions.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QT_MINIMUM_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() || m_texture_id == 0) {
+ QSGPlainTexture::bind();
+ } else {
+ glBindTexture(GL_TEXTURE_2D, m_texture_id);
+
+ 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
+
+ m_dirty_texture = false;
+ m_dirty_bind_options = false;
+ }
+ m_dirty_rect = QRect();
+}
+
+QSGPainterNode::QSGPainterNode(QSGPaintedItem *item)
+ : QSGGeometryNode()
+ , m_preferredRenderTarget(QSGPaintedItem::Image)
+ , m_actualRenderTarget(QSGPaintedItem::Image)
+ , m_item(item)
+ , m_fbo(0)
+ , m_multisampledFbo(0)
+ , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+ , m_texture(0)
+ , m_size(1, 1)
+ , m_dirtyContents(false)
+ , m_opaquePainting(false)
+ , m_linear_filtering(false)
+ , m_smoothPainting(false)
+ , m_extensionsChecked(false)
+ , m_multisamplingSupported(false)
+ , m_fillColor(Qt::transparent)
+ , m_dirtyGeometry(false)
+ , m_dirtyRenderTarget(false)
+ , m_dirtyTexture(false)
+{
+ setMaterial(&m_materialO);
+ setOpaqueMaterial(&m_material);
+ setGeometry(&m_geometry);
+ setFlag(UsePreprocess);
+}
+
+QSGPainterNode::~QSGPainterNode()
+{
+ delete m_texture;
+ delete m_fbo;
+ delete m_multisampledFbo;
+}
+
+void QSGPainterNode::preprocess()
+{
+ if (!m_dirtyContents)
+ return;
+
+ QRect dirtyRect = m_dirtyRect.isNull() ? QRect(0, 0, m_size.width(), m_size.height()) : m_dirtyRect;
+
+ QPainter painter;
+ if (m_actualRenderTarget == QSGPaintedItem::Image)
+ painter.begin(&m_image);
+ else if (m_multisampledFbo)
+ painter.begin(m_multisampledFbo);
+ else
+ painter.begin(m_fbo);
+
+ if (m_smoothPainting) {
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing
+ | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
+ }
+
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.fillRect(dirtyRect, m_fillColor);
+ painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+
+ if (!m_dirtyRect.isNull())
+ painter.setClipRect(dirtyRect);
+ m_item->paint(&painter);
+ painter.end();
+
+ if (m_actualRenderTarget == QSGPaintedItem::Image) {
+ m_texture->setImage(m_image);
+ m_texture->setDirtyRect(dirtyRect);
+ } else if (m_multisampledFbo) {
+ QGLFramebufferObject::blitFramebuffer(m_fbo, dirtyRect, m_multisampledFbo, dirtyRect);
+ }
+
+ m_dirtyContents = false;
+ m_dirtyRect = QRect();
+}
+
+void QSGPainterNode::update()
+{
+ if (m_dirtyRenderTarget)
+ updateRenderTarget();
+ if (m_dirtyGeometry)
+ updateGeometry();
+ if (m_dirtyTexture)
+ updateTexture();
+
+ m_dirtyGeometry = false;
+ m_dirtyRenderTarget = false;
+ m_dirtyTexture = false;
+}
+
+void QSGPainterNode::updateTexture()
+{
+ 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 == QSGPaintedItem::Image)
+ source = QRectF(0, 0, 1, 1);
+ else
+ source = QRectF(0, 1, qreal(m_size.width()) / m_fboSize.width(), qreal(-m_size.height()) / m_fboSize.height());
+ QSGGeometry::updateTexturedRectGeometry(&m_geometry,
+ QRectF(0, 0, m_size.width(), m_size.height()),
+ 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;
+
+ QSGPaintedItem::RenderTarget oldTarget = m_actualRenderTarget;
+ if (m_preferredRenderTarget == QSGPaintedItem::Image) {
+ m_actualRenderTarget = QSGPaintedItem::Image;
+ } else {
+ if (!m_multisamplingSupported && m_smoothPainting)
+ m_actualRenderTarget = QSGPaintedItem::Image;
+ else
+ m_actualRenderTarget = QSGPaintedItem::FramebufferObject;
+ }
+ if (oldTarget != m_actualRenderTarget) {
+ m_image = QImage();
+ delete m_fbo;
+ delete m_multisampledFbo;
+ m_fbo = m_multisampledFbo = 0;
+ }
+
+ if (m_actualRenderTarget == QSGPaintedItem::FramebufferObject) {
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (m_fbo && !m_dirtyGeometry && (!ctx->format().sampleBuffers() || !m_multisamplingSupported))
+ return;
+
+ if (m_fboSize.isEmpty())
+ updateFBOSize();
+
+ delete m_fbo;
+ delete m_multisampledFbo;
+ m_fbo = m_multisampledFbo = 0;
+
+ if (m_smoothPainting && ctx->format().sampleBuffers() && m_multisamplingSupported) {
+ {
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setSamples(ctx->format().samples());
+ m_multisampledFbo = new QGLFramebufferObject(m_fboSize, format);
+ }
+ {
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::NoAttachment);
+ m_fbo = new QGLFramebufferObject(m_fboSize, format);
+ }
+ } else {
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ m_fbo = new QGLFramebufferObject(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 == QSGPaintedItem::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;
+ m_material.setFiltering(m_linear_filtering ? QSGTexture::Linear : QSGTexture::Nearest);
+ m_materialO.setFiltering(m_linear_filtering ? QSGTexture::Linear : QSGTexture::Nearest);
+}
+
+void QSGPainterNode::updateFBOSize()
+{
+ int fboWidth = qMax(QT_MINIMUM_FBO_SIZE, qt_next_power_of_two(m_size.width()));
+ int fboHeight = qMax(QT_MINIMUM_FBO_SIZE, qt_next_power_of_two(m_size.height()));
+ m_fboSize = QSize(fboWidth, fboHeight);
+}
+
+void QSGPainterNode::setPreferredRenderTarget(QSGPaintedItem::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(bool d, const QRect &dirtyRect)
+{
+ m_dirtyContents = d;
+ m_dirtyRect = dirtyRect;
+
+ 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::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);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgpainternode_p.h b/src/declarative/scenegraph/util/qsgpainternode_p.h
new file mode 100644
index 0000000000..ef1f3f1dde
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgpainternode_p.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGPAINTERNODE_P_H
+#define QSGPAINTERNODE_P_H
+
+#include "qsgnode.h"
+#include "qsgtexturematerial.h"
+#include "qsgtexture_p.h"
+#include "qsgpainteditem.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QGLFramebufferObject;
+
+class Q_DECLARATIVE_EXPORT QSGPainterTexture : public QSGPlainTexture
+{
+public:
+ QSGPainterTexture();
+
+ void setDirtyRect(const QRect &rect) { m_dirty_rect = rect; }
+
+ void bind();
+
+private:
+ QRect m_dirty_rect;
+};
+
+class Q_DECLARATIVE_EXPORT QSGPainterNode : public QSGGeometryNode
+{
+public:
+ QSGPainterNode(QSGPaintedItem *item);
+ virtual ~QSGPainterNode();
+
+ void setPreferredRenderTarget(QSGPaintedItem::RenderTarget target);
+
+ void setSize(const QSize &size);
+ QSize size() const { return m_size; }
+
+ void setDirty(bool d, 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 setSmoothPainting(bool s);
+ bool smoothPainting() const { return m_smoothPainting; }
+
+ void setFillColor(const QColor &c);
+ QColor fillColor() const { return m_fillColor; }
+
+ void update();
+
+ void preprocess();
+
+private:
+ void updateTexture();
+ void updateGeometry();
+ void updateRenderTarget();
+ void updateFBOSize();
+
+ QSGPaintedItem::RenderTarget m_preferredRenderTarget;
+ QSGPaintedItem::RenderTarget m_actualRenderTarget;
+
+ QSGPaintedItem *m_item;
+
+ QGLFramebufferObject *m_fbo;
+ QGLFramebufferObject *m_multisampledFbo;
+ QImage m_image;
+
+ QSGTextureMaterial m_material;
+ QSGTextureMaterialWithOpacity m_materialO;
+ QSGGeometry m_geometry;
+ QSGPainterTexture *m_texture;
+
+ QSize m_size;
+ QSize m_fboSize;
+ bool m_dirtyContents;
+ QRect m_dirtyRect;
+ bool m_opaquePainting;
+ bool m_linear_filtering;
+ bool m_smoothPainting;
+ bool m_extensionsChecked;
+ bool m_multisamplingSupported;
+ QColor m_fillColor;
+
+ bool m_dirtyGeometry;
+ bool m_dirtyRenderTarget;
+ bool m_dirtyTexture;
+};
+
+QT_END_HEADER
+
+QT_END_NAMESPACE
+
+#endif // QSGPAINTERNODE_P_H
diff --git a/src/declarative/scenegraph/util/qsgsimplerectnode.cpp b/src/declarative/scenegraph/util/qsgsimplerectnode.cpp
new file mode 100644
index 0000000000..604222dad5
--- /dev/null
+++ b/src/declarative/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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/declarative/scenegraph/util/qsgsimplerectnode.h b/src/declarative/scenegraph/util/qsgsimplerectnode.h
new file mode 100644
index 0000000000..ac001ab4eb
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimplerectnode.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SOLIDRECTNODE_H
+#define SOLIDRECTNODE_H
+
+#include "qsgnode.h"
+#include "qsgflatcolormaterial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_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/declarative/scenegraph/util/qsgsimpletexturenode.cpp b/src/declarative/scenegraph/util/qsgsimpletexturenode.cpp
new file mode 100644
index 0000000000..4e4567444a
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimpletexturenode.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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, ts.height(), ts.width(), -ts.height());
+ QSGGeometry::updateTexturedRectGeometry(g, rect, texture->convertToNormalizedSourceRect(sourceRect));
+}
+
+/*!
+ \class QSGSimpleTextureNode
+ \brief The QSGSimpleTextureNode provided for convenience to easily draw
+ textured content using the QML scene graph.
+
+ \warning The simple texture node class must have 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_opaque_material);
+ setOpaqueMaterial(&m_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/declarative/scenegraph/util/qsgsimpletexturenode.h b/src/declarative/scenegraph/util/qsgsimpletexturenode.h
new file mode 100644
index 0000000000..b4d8b71962
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgsimpletexturenode.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGSIMPLETEXTURENODE_H
+#define QSGSIMPLETEXTURENODE_H
+
+#include "qsgnode.h"
+#include "qsggeometry.h"
+#include "qsgtexturematerial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_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;
+ QSGTextureMaterial m_opaque_material;
+ QSGTextureMaterialWithOpacity m_material;
+
+ QRectF m_rect;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGSIMPLETEXTURENODE_H
diff --git a/src/declarative/scenegraph/util/qsgtexture.cpp b/src/declarative/scenegraph/util/qsgtexture.cpp
new file mode 100644
index 0000000000..9362ba8bf6
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexture.cpp
@@ -0,0 +1,400 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <private/qsgtexture_p.h>
+#include <qglfunctions.h>
+#include <private/qsgcontext_p.h>
+#include <qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+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_texture_count = 0;
+
+static void qt_print_texture_count()
+{
+ qDebug("Number of leaked textures: %i", qt_texture_count);
+ qt_texture_count = -1;
+}
+#endif
+
+
+
+QSGTexture::QSGTexture()
+ : QObject(*(new QSGTexturePrivate))
+{
+#ifndef QT_NO_DEBUG
+ ++qt_texture_count;
+ static bool atexit_registered = false;
+ if (!atexit_registered) {
+ atexit(qt_print_texture_count);
+ atexit_registered = true;
+ }
+#endif
+}
+
+QSGTexture::~QSGTexture()
+{
+#ifndef QT_NO_DEBUG
+ --qt_texture_count;
+ if (qt_texture_count < 0)
+ qDebug("Material destroyed after qt_print_texture_count() was called.");
+#endif
+}
+
+
+/*!
+ \fn void QSGTexture::setImage(const QImage &image)
+
+ This function may be calld from arbitrary an arbitrary thread and may not
+ use GL calls.
+ */
+
+
+/*!
+ \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.
+ */
+
+void QSGTexture::removeFromAtlas()
+{
+ // default textures are not in atlasses, so do nothing...
+}
+
+/*!
+ Returns weither this texture is part of an atlas or not.
+
+ The default implementation returns false.
+ */
+bool QSGTexture::isAtlasTexture() const
+{
+ return false;
+}
+
+
+/*!
+ 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) {
+ 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;
+ }
+
+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) {
+ const QGLContext *ctx = QGLContext::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_texture_id && m_owns_texture)
+ glDeleteTextures(1, &m_texture_id);
+
+ if (m_image.isNull()) {
+ m_texture_id = 0;
+ m_texture_size = QSize();
+ m_has_mipmaps = false;
+ m_has_alpha = false;
+ return;
+ }
+
+ 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) {
+ const QGLContext *ctx = QGLContext::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/declarative/scenegraph/util/qsgtexture.h b/src/declarative/scenegraph/util/qsgtexture.h
new file mode 100644
index 0000000000..9b95ef36ad
--- /dev/null
+++ b/src/declarative/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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTURE_H
+#define QSGTEXTURE_H
+
+#include <QObject>
+#include <QImage>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTexturePrivate;
+class Q_DECLARATIVE_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 void removeFromAtlas();
+
+ 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 QSGDynamicTexture : public QSGTexture
+{
+ Q_OBJECT
+public:
+ virtual bool updateTexture() = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/util/qsgtexture_p.h b/src/declarative/scenegraph/util/qsgtexture_p.h
new file mode 100644
index 0000000000..2c142f5746
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexture_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTURE_P_H
+#define QSGTEXTURE_P_H
+
+#include <private/qobject_p.h>
+
+#include <QtOpenGL/qgl.h>
+
+#include "qsgtexture.h"
+#include <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_DECLARATIVE_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 { return m_texture_id; }
+
+ 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);
+
+ virtual void bind();
+
+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/declarative/scenegraph/util/qsgtexturematerial.cpp b/src/declarative/scenegraph/util/qsgtexturematerial.cpp
new file mode 100644
index 0000000000..717bf82090
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexturematerial.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgtexturematerial_p.h"
+
+#include <qglshaderprogram.h>
+
+QT_BEGIN_NAMESPACE
+
+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 *QSGTextureMaterialShader::vertexShader() const
+{
+ return qt_scenegraph_texture_material_vertex_code;
+}
+
+const char *QSGTextureMaterialShader::fragmentShader() const
+{
+ return qt_scenegraph_texture_material_fragment;
+}
+
+QSGMaterialType QSGTextureMaterialShader::type;
+
+char const *const *QSGTextureMaterialShader::attributeNames() const
+{
+ static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 };
+ return attr;
+}
+
+void QSGTextureMaterialShader::initialize()
+{
+ m_matrix_id = m_program.uniformLocation("qt_Matrix");
+}
+
+void QSGTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ QSGTextureMaterial *tx = static_cast<QSGTextureMaterial *>(newEffect);
+ QSGTextureMaterial *oldTx = static_cast<QSGTextureMaterial *>(oldEffect);
+
+ QSGTexture *t = tx->texture();
+
+ t->setFiltering(tx->filtering());
+ 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())
+ m_program.setUniformValue(m_matrix_id, state.combinedMatrix());
+}
+
+
+QSGTextureMaterial::QSGTextureMaterial()
+ : m_texture(0)
+ , m_filtering(QSGTexture::Nearest)
+ , m_mipmap_filtering(QSGTexture::Nearest)
+ , m_horizontal_wrap(QSGTexture::ClampToEdge)
+ , m_vertical_wrap(QSGTexture::ClampToEdge)
+{
+}
+
+
+
+QSGMaterialType *QSGTextureMaterial::type() const
+{
+ return &QSGTextureMaterialShader::type;
+}
+
+QSGMaterialShader *QSGTextureMaterial::createShader() const
+{
+ return new QSGTextureMaterialShader;
+}
+
+
+void QSGTextureMaterial::setTexture(QSGTexture *texture)
+{
+ m_texture = texture;
+ setFlag(Blending, m_texture ? m_texture->hasAlphaChannel() : false);
+}
+
+
+int QSGTextureMaterial::compare(const QSGMaterial *o) const
+{
+ Q_ASSERT(o && type() == o->type());
+ const QSGTextureMaterial *other = static_cast<const QSGTextureMaterial *>(o);
+ if (int diff = m_texture->textureId() - other->texture()->textureId())
+ return diff;
+ return int(m_filtering) - int(other->m_filtering);
+}
+
+// QSGTextureMaterialWithOpacity
+
+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 TextureMaterialWithOpacityShader : public QSGTextureMaterialShader
+{
+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 TextureMaterialWithOpacityShader::type;
+
+QSGMaterialType *QSGTextureMaterialWithOpacity::type() const
+{
+ return &TextureMaterialWithOpacityShader::type;
+}
+
+QSGMaterialShader *QSGTextureMaterialWithOpacity::createShader() const
+{
+ return new TextureMaterialWithOpacityShader;
+}
+
+void TextureMaterialWithOpacityShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+{
+ Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
+ if (state.isOpacityDirty())
+ m_program.setUniformValue(m_opacity_id, state.opacity());
+
+ QSGTextureMaterialShader::updateState(state, newEffect, oldEffect);
+}
+
+void TextureMaterialWithOpacityShader::initialize()
+{
+ QSGTextureMaterialShader::initialize();
+ m_opacity_id = m_program.uniformLocation("opacity");
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgtexturematerial.h b/src/declarative/scenegraph/util/qsgtexturematerial.h
new file mode 100644
index 0000000000..db8e5aa43e
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexturematerial.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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTUREMATERIAL_H
+#define TEXTUREMATERIAL_H
+
+#include "qsgmaterial.h"
+#include <qsgtexture.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+
+class Q_DECLARATIVE_EXPORT QSGTextureMaterial : public QSGMaterial
+{
+public:
+ QSGTextureMaterial();
+
+ 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_vertical_wrap: 1;
+ uint m_horizontal_wrap : 1;
+};
+
+
+class Q_DECLARATIVE_EXPORT QSGTextureMaterialWithOpacity : public QSGTextureMaterial
+{
+public:
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // TEXTUREMATERIAL_H
diff --git a/src/declarative/scenegraph/util/qsgtexturematerial_p.h b/src/declarative/scenegraph/util/qsgtexturematerial_p.h
new file mode 100644
index 0000000000..6b811c6b2e
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtexturematerial_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTUREMATERIAL_P_H
+#define TEXTUREMATERIAL_P_H
+
+#include "qsgtexturematerial.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QSGTextureMaterialShader : 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/declarative/scenegraph/util/qsgtextureprovider.cpp b/src/declarative/scenegraph/util/qsgtextureprovider.cpp
new file mode 100644
index 0000000000..b41188772e
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtextureprovider.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $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.
+ */
+
+
+/*!
+ Convenience function for casting a QObject to a QSGTextureProvider
+ */
+QSGTextureProvider *QSGTextureProvider::from(QObject *object)
+{
+ return static_cast<QSGTextureProvider *>(object->qt_metacast("QSGTextureProvider"));
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgtextureprovider_p.h b/src/declarative/scenegraph/util/qsgtextureprovider_p.h
new file mode 100644
index 0000000000..486e7d5882
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgtextureprovider_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGTEXTUREPROVIDER_H
+#define QSGTEXTUREPROVIDER_H
+
+#include <qgl.h>
+
+#include "qsgtexture.h"
+#include "qobject.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGTextureProvider
+{
+public:
+ virtual QSGTexture *texture() const = 0;
+ virtual const char *textureChangedSignal() const { return 0; }
+
+ static QSGTextureProvider *from(QObject *object);
+};
+Q_DECLARE_INTERFACE(QSGTextureProvider, "QSGTextureProvider")
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp b/src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp
new file mode 100644
index 0000000000..bbd57ea1c2
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgvertexcolormaterial.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgvertexcolormaterial_p.h"
+
+#include <qglshaderprogram.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())
+ m_program.setUniformValue(m_opacity_id, state.opacity());
+
+ if (state.isMatrixDirty())
+ m_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 = m_program.uniformLocation("matrix");
+ m_opacity_id = m_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"
+ "}";
+}
+
+
+QSGVertexColorMaterial::QSGVertexColorMaterial(bool opaque) : m_opaque(opaque)
+{
+ setFlag(Blending, !opaque);
+}
+
+void QSGVertexColorMaterial::setOpaque(bool opaque)
+{
+ setFlag(Blending, !opaque);
+ m_opaque = opaque;
+}
+
+QSGMaterialType *QSGVertexColorMaterial::type() const
+{
+ return &QSGVertexColorMaterialShader::type;
+}
+
+QSGMaterialShader *QSGVertexColorMaterial::createShader() const
+{
+ return new QSGVertexColorMaterialShader;
+}
+
+bool QSGVertexColorMaterial::is(const QSGMaterial *effect)
+{
+ return effect->type() == &QSGVertexColorMaterialShader::type;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h b/src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h
new file mode 100644
index 0000000000..9f5e0ed1db
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgvertexcolormaterial_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VERTEXCOLORMATERIAL_H
+#define VERTEXCOLORMATERIAL_H
+
+#include <qsgmaterial.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QSGVertexColorMaterial : public QSGMaterial
+{
+public:
+ QSGVertexColorMaterial(bool opaque = false);
+ virtual QSGMaterialType *type() const;
+ virtual QSGMaterialShader *createShader() const;
+
+ void setOpaque(bool opaque);
+ bool opaque() const { return m_opaque; }
+
+ static bool is(const QSGMaterial *effect);
+
+private:
+ bool m_opaque;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // VERTEXCOLORMATERIAL_H