aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/coreapi
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/coreapi')
-rw-r--r--src/quick/scenegraph/coreapi/qsgdefaultrenderer.cpp527
-rw-r--r--src/quick/scenegraph/coreapi/qsgdefaultrenderer_p.h119
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.cpp466
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.h294
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry_p.h73
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp535
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.h143
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp1264
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.h346
-rw-r--r--src/quick/scenegraph/coreapi/qsgnodeupdater.cpp287
-rw-r--r--src/quick/scenegraph/coreapi/qsgnodeupdater_p.h86
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp743
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer_p.h232
13 files changed, 5115 insertions, 0 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgdefaultrenderer.cpp b/src/quick/scenegraph/coreapi/qsgdefaultrenderer.cpp
new file mode 100644
index 0000000000..56a6e0e5d9
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgdefaultrenderer.cpp
@@ -0,0 +1,527 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#define GL_GLEXT_PROTOTYPES
+
+#include "qsgdefaultrenderer_p.h"
+#include "qsgmaterial.h"
+
+#include <QtCore/qvarlengtharray.h>
+#include <QtGui/qguiapplication.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();
+}
+
+
+QSGDefaultRenderer::IndexGeometryNodePair::IndexGeometryNodePair(int i, QSGGeometryNode *node)
+ : QPair<int, QSGGeometryNode *>(i, node)
+{
+}
+
+bool QSGDefaultRenderer::IndexGeometryNodePair::operator < (const QSGDefaultRenderer::IndexGeometryNodePair &other) const
+{
+ return nodeLessThan(second, other.second);
+}
+
+
+QSGDefaultRenderer::IndexGeometryNodePairHeap::IndexGeometryNodePairHeap()
+ : v(64)
+{
+}
+
+void QSGDefaultRenderer::IndexGeometryNodePairHeap::insert(const QSGDefaultRenderer::IndexGeometryNodePair &x)
+{
+ int i = v.size();
+ v.add(x);
+ while (i != 0 && v.at(i) < v.at(parent(i))) {
+ qSwap(v.at(parent(i)), v.at(i));
+ i = parent(i);
+ }
+}
+
+QSGDefaultRenderer::IndexGeometryNodePair QSGDefaultRenderer::IndexGeometryNodePairHeap::pop()
+{
+ IndexGeometryNodePair x = top();
+ if (v.size() > 1)
+ qSwap(v.first(), v.last());
+ v.pop_back();
+ int i = 0;
+ while (left(i) < v.size()) {
+ int low = left(i);
+ if (right(i) < v.size() && v.at(right(i)) < v.at(low))
+ low = right(i);
+ if (!(v.at(low) < v.at(i)))
+ break;
+ qSwap(v.at(i), v.at(low));
+ i = low;
+ }
+ return x;
+}
+
+
+QSGDefaultRenderer::QSGDefaultRenderer(QSGContext *context)
+ : QSGRenderer(context)
+ , m_opaqueNodes(64)
+ , m_transparentNodes(64)
+ , m_tempNodes(64)
+ , 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 QSGDefaultRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyFlags flags)
+{
+ QSGRenderer::nodeChanged(node, flags);
+
+ quint32 rebuildFlags = QSGNode::DirtyNodeAdded | QSGNode::DirtyNodeRemoved
+ | QSGNode::DirtyMaterial | QSGNode::DirtyOpacity
+ | QSGNode::DirtyForceUpdate;
+
+ if (flags & rebuildFlags)
+ m_rebuild_lists = true;
+
+ if (flags & (rebuildFlags | QSGNode::DirtyClipList))
+ m_needs_sorting = true;
+}
+
+void QSGDefaultRenderer::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_current_projection_matrix = projectionMatrix();
+ m_current_model_view_matrix.setToIdentity();
+
+ m_currentClip = 0;
+ glDisable(GL_STENCIL_TEST);
+
+ m_currentMaterial = 0;
+ m_currentProgram = 0;
+ m_currentMatrix = 0;
+
+ if (m_rebuild_lists) {
+ m_opaqueNodes.reset();
+ m_transparentNodes.reset();
+ m_currentRenderOrder = 1;
+ buildLists(rootNode());
+ m_rebuild_lists = false;
+ }
+
+#ifdef RENDERER_DEBUG
+ int debugtimeLists = debugTimer.elapsed();
+#endif
+
+
+ if (m_needs_sorting) {
+ if (!m_opaqueNodes.isEmpty()) {
+ qSort(&m_opaqueNodes.first(), &m_opaqueNodes.first() + m_opaqueNodes.size(),
+ 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();
+
+#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
+
+}
+
+void QSGDefaultRenderer::setSortFrontToBackEnabled(bool sort)
+{
+ printf("setting sorting to... %d\n", sort);
+ m_sort_front_to_back = sort;
+}
+
+bool QSGDefaultRenderer::isSortFrontToBackEnabled() const
+{
+ return m_sort_front_to_back;
+}
+
+void QSGDefaultRenderer::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.add(geomNode);
+ } else {
+ geomNode->setRenderOrder(m_currentRenderOrder);
+ m_opaqueNodes.add(geomNode);
+ m_currentRenderOrder += 2;
+ }
+ }
+
+ if (!node->firstChild())
+ return;
+
+#ifdef FORCE_NO_REORDER
+ static bool reorder = false;
+#else
+ static bool reorder = qApp->arguments().contains(QLatin1String("--reorder"));
+#endif
+
+ if (reorder && node->firstChild() != node->lastChild() && (node->flags() & QSGNode::ChildrenDoNotOverlap)) {
+ QVarLengthArray<int, 16> beginIndices;
+ QVarLengthArray<int, 16> endIndices;
+ int baseCount = m_transparentNodes.size();
+ int count = 0;
+ for (QSGNode *c = node->firstChild(); c; c = c->nextSibling()) {
+ beginIndices.append(m_transparentNodes.size());
+ buildLists(c);
+ endIndices.append(m_transparentNodes.size());
+ ++count;
+ }
+
+ int childNodeCount = m_transparentNodes.size() - baseCount;
+ if (childNodeCount) {
+ m_tempNodes.reset();
+ m_tempNodes.reserve(childNodeCount);
+ while (childNodeCount) {
+ for (int i = 0; i < count; ++i) {
+ if (beginIndices[i] != endIndices[i])
+ m_heap.insert(IndexGeometryNodePair(i, m_transparentNodes.at(beginIndices[i]++)));
+ }
+ while (!m_heap.isEmpty()) {
+ IndexGeometryNodePair pair = m_heap.pop();
+ m_tempNodes.add(pair.second);
+ --childNodeCount;
+ int i = pair.first;
+ if (beginIndices[i] != endIndices[i] && !nodeLessThan(m_transparentNodes.at(beginIndices[i]), pair.second))
+ m_heap.insert(IndexGeometryNodePair(i, m_transparentNodes.at(beginIndices[i]++)));
+ }
+ }
+ Q_ASSERT(m_tempNodes.size() == m_transparentNodes.size() - baseCount);
+
+ qMemCopy(&m_transparentNodes.at(baseCount), &m_tempNodes.at(0), m_tempNodes.size() * sizeof(QSGGeometryNode *));
+ }
+ } else {
+ for (QSGNode *c = node->firstChild(); c; c = c->nextSibling())
+ buildLists(c);
+ }
+}
+
+void QSGDefaultRenderer::renderNodes(const QDataBuffer<QSGGeometryNode *> &list)
+{
+ const float scale = 1.0f / m_currentRenderOrder;
+ int count = list.size();
+ int currentRenderOrder = 0x80000000;
+ m_current_projection_matrix.setColumn(2, scale * projectionMatrix().column(2));
+
+ //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_current_model_view_matrix = *m_currentMatrix;
+ else
+ m_current_model_view_matrix.setToIdentity();
+ updates |= QSGMaterialShader::RenderState::DirtyMatrix;
+ }
+
+ bool changeOpacity = m_current_opacity != geomNode->inheritedOpacity();
+ if (changeOpacity) {
+ updates |= QSGMaterialShader::RenderState::DirtyOpacity;
+ m_current_opacity = geomNode->inheritedOpacity();
+ }
+
+ Q_ASSERT(geomNode->activeMaterial());
+
+ QSGMaterial *material = geomNode->activeMaterial();
+ QSGMaterialShader *program = m_context->prepareMaterial(material);
+ Q_ASSERT(program->program()->isLinked());
+
+ bool changeClip = geomNode->clipList() != m_currentClip;
+ QSGRenderer::ClipType clipType = QSGRenderer::NoClip;
+ if (changeClip) {
+ // The clip function relies on there not being any depth testing..
+ glDisable(GL_DEPTH_TEST);
+ clipType = updateStencilClip(geomNode->clipList());
+ glEnable(GL_DEPTH_TEST);
+ m_currentClip = geomNode->clipList();
+#ifdef FORCE_NO_REORDER
+ glDepthMask(false);
+#else
+ glDepthMask((material->flags() & QSGMaterial::Blending) == 0 && m_current_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_current_projection_matrix.setColumn(3, projectionMatrix().column(3)
+ + currentRenderOrder
+ * m_current_projection_matrix.column(2));
+ 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();
+ draw(program, g);
+
+#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/quick/scenegraph/coreapi/qsgdefaultrenderer_p.h b/src/quick/scenegraph/coreapi/qsgdefaultrenderer_p.h
new file mode 100644
index 0000000000..a4c2ffbdbc
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgdefaultrenderer_p.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLRENDERER_H
+#define QMLRENDERER_H
+
+#include "qsgrenderer_p.h"
+
+#include <QtGui/private/qdatabuffer_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGDefaultRenderer : public QSGRenderer
+{
+ Q_OBJECT
+public:
+ class IndexGeometryNodePair : public QPair<int, QSGGeometryNode *>
+ {
+ public:
+ IndexGeometryNodePair(int i, QSGGeometryNode *n);
+ bool operator < (const IndexGeometryNodePair &other) const;
+ };
+
+
+ // Minimum heap.
+ class IndexGeometryNodePairHeap
+ {
+ public:
+ IndexGeometryNodePairHeap();
+ void insert(const IndexGeometryNodePair &x);
+ const IndexGeometryNodePair &top() const { return v.first(); }
+ IndexGeometryNodePair 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; }
+ QDataBuffer<IndexGeometryNodePair> v;
+ };
+
+ QSGDefaultRenderer(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 QDataBuffer<QSGGeometryNode *> &list);
+
+ const QSGClipNode *m_currentClip;
+ QSGMaterial *m_currentMaterial;
+ QSGMaterialShader *m_currentProgram;
+ const QMatrix4x4 *m_currentMatrix;
+ QMatrix4x4 m_renderOrderMatrix;
+ QDataBuffer<QSGGeometryNode *> m_opaqueNodes;
+ QDataBuffer<QSGGeometryNode *> m_transparentNodes;
+ QDataBuffer<QSGGeometryNode *> m_tempNodes;
+ IndexGeometryNodePairHeap m_heap;
+
+ 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/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp
new file mode 100644
index 0000000000..8661c9af93
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp
@@ -0,0 +1,466 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsggeometry.h"
+#include "qsggeometry_p.h"
+
+#include <qopenglcontext.h>
+#include <qopenglfunctions.h>
+#include <private/qopenglextensions_p.h>
+
+QT_BEGIN_NAMESPACE
+
+
+QSGGeometry::Attribute QSGGeometry::Attribute::create(int attributeIndex, int tupleSize, int primitiveType, bool isPrimitive)
+{
+ Attribute a = { attributeIndex, tupleSize, primitiveType, isPrimitive, 0 };
+ return a;
+}
+
+
+/*!
+ Convenience function which returns attributes to be used for 2D solid
+ color drawing.
+ */
+
+const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_Point2D()
+{
+ static Attribute data[] = {
+ QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true)
+ };
+ 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[] = {
+ QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
+ QSGGeometry::Attribute::create(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[] = {
+ QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
+ QSGGeometry::Attribute::create(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_server_data(0)
+ , m_owns_data(false)
+ , m_index_usage_pattern(AlwaysUploadPattern)
+ , m_vertex_usage_pattern(AlwaysUploadPattern)
+{
+ Q_ASSERT(m_attributes.count > 0);
+ Q_ASSERT(m_attributes.stride > 0);
+
+ Q_ASSERT_X(indexType != GL_UNSIGNED_INT
+ || static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions())
+ ->hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint),
+ "QSGGeometry::QSGGeometry",
+ "GL_UNSIGNED_INT is not supported, geometry will not render"
+ );
+
+ if (indexType != GL_UNSIGNED_BYTE
+ && indexType != GL_UNSIGNED_SHORT
+ && indexType != GL_UNSIGNED_INT) {
+ qFatal("QSGGeometry: Unsupported index type, %x.\n", indexType);
+ }
+
+
+ // Because allocate reads m_vertex_count, m_index_count and m_owns_data, these
+ // need to be set before calling allocate...
+ allocate(vertexCount, indexCount);
+}
+
+/*!
+ \fn int QSGGeometry::sizeOfVertex() const
+
+ Returns the size in bytes of one vertex.
+
+ This value comes from the attributes.
+ */
+
+/*!
+ \fn int QSGGeometry::sizeOfIndex() const
+
+ Returns the byte size of the index type.
+
+ This value is either 1 when index type is GL_UNSIGNED_BYTE or 2 when
+ index type is GL_UNSIGNED_SHORT. For Desktop OpenGL, GL_UNSIGNED_INT
+ with the value 4 is also supported.
+ */
+
+QSGGeometry::~QSGGeometry()
+{
+ if (m_owns_data)
+ qFree(m_data);
+
+ if (m_server_data)
+ delete m_server_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;
+ }
+
+ // If we have associated vbo data we could potentially crash later if
+ // the old buffers are used with the new vertex and index count, so we force
+ // an update in the renderer in that case. This is really the users responsibility
+ // but it is cheap for us to enforce this, so why not...
+ if (m_server_data) {
+ markIndexDataDirty();
+ markVertexDataDirty();
+ }
+
+}
+
+/*!
+ 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();
+}
+
+
+
+/*!
+ \enum QSGGeometry::DataPattern
+
+ The DataPattern enum is used to specify the use pattern for the vertex
+ and index data in a geometry object.
+
+ \value AlwaysUploadPattern The data is always uploaded. This means that
+ the user does not need to explicitly mark index and vertex data as
+ dirty after changing it. This is the default.
+
+ \value DynamicPattern The data is modified repeatedly and drawn many times.
+ This is a hint that may provide better performance. When set
+ the user must make sure to mark the data as dirty after changing it.
+
+ \value StaticPattern The data is modified once and drawn many times. This is
+ a hint that may provide better performance. When set the user must make sure
+ to mark the data as dirty after changing it.
+ */
+
+
+/*!
+ \fn QSGGeometry::DataPattern QSGGeometry::indexDataPattern() const
+
+ Returns the usage pattern for indices in this geometry. The default
+ pattern is AlwaysUploadPattern.
+ */
+
+/*!
+ Sets the usage pattern for indices to \a p.
+
+ The default is AlwaysUploadPattern. When set to anything other than
+ the default, the user must call markIndexDataDirty() after changing
+ the index data.
+ */
+
+void QSGGeometry::setIndexDataPattern(DataPattern p)
+{
+ m_index_usage_pattern = p;
+}
+
+
+
+
+/*!
+ \fn QSGGeometry::DataPattern QSGGeometry::vertexDataPattern() const
+
+ Returns the usage pattern for vertices in this geometry. The default
+ pattern is AlwaysUploadPattern.
+ */
+
+/*!
+ Sets the usage pattern for vertices to \a p.
+
+ The default is AlwaysUploadPattern. When set to anything other than
+ the default, the user must call markVertexDataDirty() after changing
+ the vertex data.
+ */
+
+void QSGGeometry::setVertexDataPattern(DataPattern p)
+{
+ m_vertex_usage_pattern = p;
+}
+
+
+
+
+/*!
+ Mark that the vertices in this geometry has changed and must be uploaded
+ again.
+
+ This function only has an effect when the usage pattern for vertices is
+ StaticData and the renderer that renders this geometry uploads the geometry
+ into Vertex Buffer Objects (VBOs).
+ */
+void QSGGeometry::markIndexDataDirty()
+{
+ m_dirty_index_data = true;
+}
+
+
+
+/*!
+ Mark that the vertices in this geometry has changed and must be uploaded
+ again.
+
+ This function only has an effect when the usage pattern for vertices is
+ StaticData and the renderer that renders this geometry uploads the geometry
+ into Vertex Buffer Objects (VBOs).
+ */
+void QSGGeometry::markVertexDataDirty()
+{
+ m_dirty_vertex_data = true;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.h b/src/quick/scenegraph/coreapi/qsggeometry.h
new file mode 100644
index 0000000000..aea6f0b94b
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsggeometry.h
@@ -0,0 +1,294 @@
+/****************************************************************************
+**
+** 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$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGGEOMETRY_H
+#define QSGGEOMETRY_H
+
+#include <QtQuick/qtquickglobal.h>
+#include <QtGui/qopengl.h>
+#include <QRectF>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGGeometryData;
+
+class Q_QUICK_EXPORT QSGGeometry
+{
+public:
+
+ struct Attribute
+ {
+ int position;
+ int tupleSize;
+ int type;
+
+ uint isVertexCoordinate : 1;
+ uint migrateYourCodeToUseTheCreateFunction: 31; // ### Remove before release
+
+ static Attribute create(int pos, int tupleSize, int primitiveType, bool isPosition = false);
+ };
+
+ 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();
+
+ enum DataPattern {
+ AlwaysUploadPattern = 0,
+ StreamPattern = 1,
+ DynamicPattern = 2,
+ StaticPattern = 3
+ };
+
+ 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();
+
+ inline int sizeOfIndex() const;
+
+ 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 sizeOfVertex() const { return m_attributes.stride; }
+
+ static void updateRectGeometry(QSGGeometry *g, const QRectF &rect);
+ static void updateTexturedRectGeometry(QSGGeometry *g, const QRectF &rect, const QRectF &sourceRect);
+
+ void setIndexDataPattern(DataPattern p);
+ DataPattern indexDataPattern() const { return (DataPattern) m_index_usage_pattern; }
+
+ void setVertexDataPattern(DataPattern p);
+ DataPattern vertexDataPattern() const { return (DataPattern) m_vertex_usage_pattern; }
+
+ void markIndexDataDirty();
+ void markVertexDataDirty();
+
+private:
+ friend class QSGGeometryData;
+
+ 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;
+
+ QSGGeometryData *m_server_data;
+
+ uint m_owns_data : 1;
+ uint m_index_usage_pattern : 2;
+ uint m_vertex_usage_pattern : 2;
+ uint m_dirty_index_data : 1;
+ uint m_dirty_vertex_data : 1;
+ uint m_reserved_bits : 27;
+
+ 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;
+}
+
+int QSGGeometry::sizeOfIndex() const
+{
+ if (m_index_type == GL_UNSIGNED_SHORT) return 2;
+ else if (m_index_type == GL_UNSIGNED_BYTE) return 1;
+ else if (m_index_type == GL_UNSIGNED_INT) return 4;
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSGGEOMETRY_H
diff --git a/src/quick/scenegraph/coreapi/qsggeometry_p.h b/src/quick/scenegraph/coreapi/qsggeometry_p.h
new file mode 100644
index 0000000000..ef2935ae4c
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsggeometry_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGGEOMETRY_P_H
+#define QSGGEOMETRY_P_H
+
+#include "qsggeometry.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSGGeometryData
+{
+public:
+ virtual ~QSGGeometryData() {}
+
+ static inline QSGGeometryData *data(const QSGGeometry *g) {
+ return g->m_server_data;
+ }
+
+ static inline void install(const QSGGeometry *g, QSGGeometryData *data) {
+ Q_ASSERT(!g->m_server_data);
+ const_cast<QSGGeometry *>(g)->m_server_data = data;
+ }
+
+ static bool inline hasDirtyVertexData(const QSGGeometry *g) { return g->m_dirty_vertex_data; }
+ static void inline clearDirtyVertexData(const QSGGeometry *g) { const_cast<QSGGeometry *>(g)->m_dirty_vertex_data = false; }
+
+ static bool inline hasDirtyIndexData(const QSGGeometry *g) { return g->m_dirty_vertex_data; }
+ static void inline clearDirtyIndexData(const QSGGeometry *g) { const_cast<QSGGeometry *>(g)->m_dirty_index_data = false; }
+
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGGEOMETRY_P_H
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
new file mode 100644
index 0000000000..36b50e89b6
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -0,0 +1,535 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgmaterial.h"
+#include "qsgrenderer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+/*!
+ \class QSGMaterialShader
+ \brief The QSGMaterialShader class implements a material renders geometry.
+
+ The QSGMaterial and QSGMaterialShader form a tight relationship. For one
+ scene graph (including nested graphs), there is one unique QSGMaterialShader
+ instance which encapsulates the QOpenGLShaderProgram the scene graph uses
+ to render that material, such as a shader to flat coloring of geometry.
+ Each QSGGeometryNode can have a unique QSGMaterial containing the
+ how the shader should be configured when drawing that node, such as
+ the actual color to used to render the geometry.
+
+ An instance of QSGMaterialShader is never created explicitely by the user,
+ it will be created on demand by the scene graph through
+ QSGMaterial::createShader(). The scene graph will make sure that there
+ is only one instance of each shader implementation through a scene graph.
+
+ The source code returned from vertexShader() is used to control what the
+ material does with the vertiex data that comes in from the geometry.
+ The source code returned from the fragmentShader() is used to control
+ what how the material should fill each individual pixel in the geometry.
+ The vertex and fragment source code is queried once during initialization,
+ changing what is returned from these functions later will not have
+ any effect.
+
+ The activate() function is called by the scene graph when a shader is
+ is starting to be used. The deactivate function is called by the scene
+ graph when the shader is no longer going to be used. While active,
+ the scene graph may make one or more calls to updateState() which
+ will update the state of the shader for each individual geometry to
+ render.
+
+ The attributeNames() returns the name of the attributes used in the
+ vertexShader(). These are used in the default implementation of
+ activate() and deactive() to decide whice vertex registers are enabled.
+
+ The initialize() function is called during program creation to allow
+ subclasses to prepare for use, such as resolve uniform names in the
+ vertexShader() and fragmentShader().
+
+ A minimal example:
+ \code
+ class Shader : public QSGMaterialShader
+ {
+ public:
+ const char *vertexShader() const {
+ return
+ "attribute highp vec4 vertex; \n"
+ "uniform highp mat4 matrix; \n"
+ "void main() { \n"
+ " gl_Position = matrix * vertex; \n"
+ "}";
+ }
+
+ const char *fragmentShader() const {
+ return
+ "uniform lowp float opacity; \n"
+ "void main() { \n"
+ " gl_FragColor = vec4(1, 0, 0, 1) * opacity; \n"
+ "}";
+ }
+
+ char const *const *attributeNames() const
+ {
+ static char const *const names[] = { "vertex", 0 };
+ return names;
+ }
+
+ void initialize()
+ {
+ QSGMaterialShader::initialize();
+ m_id_matrix = program()->uniformLocation("matrix");
+ m_id_opacity = program()->uniformLocation("opacity");
+ }
+
+ void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+ {
+ Q_ASSERT(program()->isLinked());
+ if (state.isMatrixDirty())
+ program()->setUniformValue(m_id_matrix, state.combinedMatrix());
+ if (state.isOpacityDirty())
+ program()->setUniformValue(m_id_opacity, state.opacity());
+ }
+
+ private:
+ int m_id_matrix;
+ int m_id_opacity;
+ };
+ \endcode
+
+ \warning Instances of QSGMaterialShader belongs to the Scene Graph rendering
+ thread, and cannot be used from the GUI thread.
+
+ */
+
+
+
+/*!
+ Creates a new QSGMaterialShader.
+ */
+QSGMaterialShader::QSGMaterialShader()
+{
+}
+
+
+
+/*!
+ \fn QOpenGLShaderProgram *QSGMaterialShader::program() const
+
+ Returns the shader program used by this QSGMaterialShader.
+ */
+
+
+
+/*!
+ This function is called by the scene graph to indicate that geometry is
+ about to be rendered using this shader.
+
+ State that is global for all uses of the shader, independent of the geometry
+ that is being drawn, can be setup in this function.
+
+ If reimplemented, make sure to either call the base class implementation to
+ enable the vertex attribute registers.
+ */
+
+void QSGMaterialShader::activate()
+{
+ Q_ASSERT(program()->isLinked());
+
+ program()->bind();
+ char const *const *attr = attributeNames();
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ program()->enableAttributeArray(i);
+ }
+}
+
+
+
+/*!
+ This function is called by the scene graph to indicate that geometry will
+ no longer to be rendered using this shader.
+
+ If reimplemented, make sure to either call the base class implementation to
+ disable the vertex attribute registers.
+ */
+
+void QSGMaterialShader::deactivate()
+{
+ char const *const *attr = attributeNames();
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ program()->disableAttributeArray(i);
+ }
+}
+
+
+
+/*!
+ This function is called by the scene graph before geometry is rendered
+ to make sure the shader is in the right state.
+
+ The current rendering \a state is passed from the scene graph. If the state
+ indicates that any state is dirty, the updateState implementation must
+ update accordingly for the geometry to render correctly.
+
+ The subclass specific state, such as the color of a flat color material, should
+ be extracted from \a newMaterial to update the color uniforms accordingly.
+
+ The \a oldMaterial can be used to minimze state changes when updating
+ material states. The \a oldMaterial is 0 if this shader was just activated.
+
+ \sa activate(), deactivate()
+ */
+
+void QSGMaterialShader::updateState(const RenderState & /* state */, QSGMaterial * /* newMaterial */, QSGMaterial * /* oldMaterial */)
+{
+}
+
+
+
+/*!
+ This function is called when the shader is initialized to compile the
+ actual QOpenGLShaderProgram. Do not call it explicitely.
+
+ The default implementation will extract the vertexShader() and
+ fragmentShader() and bind the names returned from attributeNames()
+ to consecutive vertex attribute registers starting at 0.
+ */
+
+void QSGMaterialShader::compile()
+{
+ Q_ASSERT_X(!m_program.isLinked(), "QSGSMaterialShader::compile()", "Compile called multiple times!");
+
+ program()->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader());
+ program()->addShaderFromSourceCode(QOpenGLShader::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])
+ program()->bindAttributeLocation(attr[i], i);
+ }
+#else
+ for (int i = 0; attr[i]; ++i) {
+ if (*attr[i])
+ program()->bindAttributeLocation(attr[i], i);
+ }
+#endif
+
+ if (!program()->link()) {
+ qWarning("QSGMaterialShader: Shader compilation failed:");
+ qWarning() << program()->log();
+ }
+}
+
+
+
+/*!
+ \class QSGMaterialShader::RenderState
+ \brief The QSGMaterialShader::RenderState encapsulates the current rendering state
+ during a call to QSGMaterialShader::updateState().
+
+ The render state contains a number of accessors that the shader needs to respect
+ in order to conform to the current state of the scene graph.
+
+ The instance is only valid inside a call to QSGMaterialShader::updateState() and
+ should not be used outisde this function.
+ */
+
+
+
+/*!
+ \enum QSGMaterialShader::RenderState::DirtyState
+
+ \value DirtyMatrix Used to indicate that the matrix has changed and must be updated.
+
+ \value DirtyOpacity Used to indicate that the opacity has changed and must be updated.
+ */
+
+
+
+/*!
+ \fn bool QSGMaterialShader::RenderState::isMatrixDirty() const
+
+ Convenience function to check if the dirtyStates() indicates that the matrix
+ needs to be updated.
+ */
+
+
+
+/*!
+ \fn bool QSGMaterialShader::RenderState::isOpacityDirty() const
+
+ Conveience function to check if the dirtyStates() indicates that the opacity
+ needs to be updated.
+ */
+
+
+
+/*!
+ \fn QSGMaterialShader::RenderState::DirtyStates QSGMaterialShader::RenderState::dirtyStates() const
+
+ Returns which rendering states that have changed and needs to be updated
+ for geometry rendered with this material to conform to the current
+ rendering state.
+ */
+
+
+
+/*!
+ Returns the accumulated opacity to be used for rendering
+ */
+
+float QSGMaterialShader::RenderState::opacity() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->currentOpacity();
+}
+
+
+
+/*!
+ Returns the matrix combined of modelview matrix and project matrix.
+ */
+
+QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->currentCombinedMatrix();
+}
+
+
+
+/*!
+ Returns the model view matrix.
+ */
+
+QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix();
+}
+
+
+
+/*!
+ Returns the viewport rect of the surface being rendered to.
+ */
+
+QRect QSGMaterialShader::RenderState::viewportRect() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->viewportRect();
+}
+
+
+
+/*!
+ Returns the device rect of the surface being rendered to
+ */
+
+QRect QSGMaterialShader::RenderState::deviceRect() const
+{
+ Q_ASSERT(m_data);
+ return static_cast<const QSGRenderer *>(m_data)->deviceRect();
+}
+
+
+
+/*!
+ Returns the QOpenGLContext that is being used for rendering
+ */
+
+QOpenGLContext *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
+
+/*!
+ \class QSGMaterialType
+ \brief The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
+
+ It serves no purpose outside the QSGMaterial::type() function.
+ */
+
+/*!
+ \class QSGMaterial
+ \brief The QSGMaterial class encapsulates rendering state for a shader program.
+
+ The QSGMaterial and QSGMaterialShader subclasses form a tight relationship. For
+ one scene graph (including nested graphs), there is one unique QSGMaterialShader
+ instance which encapsulates the QOpenGLShaderProgram the scene graph uses
+ to render that material, such as a shader to flat coloring of geometry.
+ Each QSGGeometryNode can have a unique QSGMaterial containing the
+ how the shader should be configured when drawing that node, such as
+ the actual color to used to render the geometry.
+
+ The QSGMaterial has two virtual functions that both need to be implemented.
+ The function type() should return a unique instance for all instances of a
+ specific subclass. The createShader() function should return a new instance
+ of QSGMaterialShader, specific to the subclass of QSGMaterial.
+
+ A minimal QSGMaterial implementation could look like this:
+ \code
+ class Material : public QSGMaterial
+ {
+ public:
+ QSGMaterialType *type() const { static QSGMaterialType type; return &type; }
+ QSGMaterialShader *createShader() const { return new Shader; }
+ };
+ \endcode
+
+ \warning Instances of QSGMaterial belongs to the Scene Graph rendering thread,
+ and cannot be used from the GUI thread.
+ */
+
+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
+}
+
+
+
+/*!
+ \enum QSGMaterial::Flag
+
+ \value Blending Set this flag to true if the material requires GL_BLEND to be
+ enabled during rendering.
+ */
+
+
+
+/*!
+ Sets the flags \a flags on this material if \a on is true;
+ otherwise clears the attribute.
+*/
+
+void QSGMaterial::setFlag(Flags flags, bool on)
+{
+ if (on)
+ m_flags |= flags;
+ else
+ m_flags &= ~flags;
+}
+
+
+
+/*!
+ Compares this material to \a other and returns 0 if they are equal; -1 if
+ this material should sort before \a other and 1 if \a other should sort
+ before.
+
+ The scene graph can reorder geometry nodes to minimize state changes.
+ The compare function is called during the sorting process so that
+ the materials can be sorted to minimize state changes in each
+ call to QSGMaterialShader::updateState().
+
+ The this pointer and \a other is guaranteed to have the same type().
+ */
+
+int QSGMaterial::compare(const QSGMaterial *other) const
+{
+ Q_ASSERT(other && type() == other->type());
+ return qint64(this) - qint64(other);
+}
+
+
+
+/*!
+ \fn QSGMaterialType QSGMaterial::type() const
+
+ This function is called by the scene graph to return a unique instance
+ per subclass.
+ */
+
+
+
+/*!
+ \fn QSGMaterialShader *QSGMaterial::createShader() const
+
+ This function returns a new instance of a the QSGMaterialShader
+ implementatation used to render geometry for a specifc implementation
+ of QSGMaterial.
+
+ The function will be called only once for each material type that
+ exists in the scene graph and will be cached internally.
+*/
+
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.h b/src/quick/scenegraph/coreapi/qsgmaterial.h
new file mode 100644
index 0000000000..d8411b4d88
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MATERIAL_H
+#define MATERIAL_H
+
+#include <QtQuick/qtquickglobal.h>
+#include <qopenglshaderprogram.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGMaterial;
+
+class Q_QUICK_EXPORT QSGMaterialShader
+{
+public:
+ class Q_QUICK_EXPORT RenderState {
+ public:
+ enum DirtyState
+ {
+ DirtyMatrix = 0x0001,
+ DirtyOpacity = 0x0002
+ };
+ Q_DECLARE_FLAGS(DirtyStates, DirtyState)
+
+ inline DirtyStates dirtyStates() 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;
+
+ QOpenGLContext *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.
+
+ inline QOpenGLShaderProgram *program() { return &m_program; }
+
+protected:
+
+ friend class QSGContext;
+
+ virtual void compile();
+ virtual void initialize() { }
+
+ virtual const char *vertexShader() const = 0;
+ virtual const char *fragmentShader() const = 0;
+
+private:
+ QOpenGLShaderProgram m_program;
+ void *m_reserved;
+};
+
+struct QSGMaterialType { };
+
+class Q_QUICK_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; }
+ void setFlag(Flags flags, bool on = true);
+
+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/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
new file mode 100644
index 0000000000..2d6828323c
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -0,0 +1,1264 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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
+ \brief The QSGNode class is the base class for all nodes in the scene graph.
+
+ \inmodule QtQuick
+
+ The QSGNode class can be used as a child container. Children are added with
+ the appendChildNode(), prependChildNode(), insertChildNodeBefore() and
+ insertChildNodeAfter(). Ordering of nodes is important as geometry nodes
+ will be rendered in the order they are added to the scene graph.
+ 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_type(BasicNodeType)
+ , m_firstChild(0)
+ , m_lastChild(0)
+ , m_nextSibling(0)
+ , m_previousSibling(0)
+ , m_subtreeGeometryCount(0)
+ , m_nodeFlags(OwnedByParent)
+ , m_flags(0)
+{
+ init();
+}
+
+QSGNode::QSGNode(NodeType type)
+ : m_parent(0)
+ , m_type(type)
+ , m_firstChild(0)
+ , m_lastChild(0)
+ , m_nextSibling(0)
+ , m_previousSibling(0)
+ , m_subtreeGeometryCount(type == GeometryNodeType ? 1 : 0)
+ , m_nodeFlags(OwnedByParent)
+ , m_flags(0)
+{
+ init();
+}
+
+void QSGNode::init()
+{
+#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("Node 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.
+ */
+
+
+
+
+/*!
+ 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.
+ */
+
+bool QSGNode::isSubtreeBlocked() const
+{
+ return m_subtreeGeometryCount == 0;
+}
+
+/*!
+ \internal
+ Detaches the node from the scene graph and deletes any children it owns.
+
+ This function is called from QSGNode's and QSGRootNode's destructor. It
+ should not be called explicitly in user code. QSGRootNode needs to call
+ destroy() because destroy() calls removeChildNode() which in turn calls
+ markDirty() which type-casts the node to QSGRootNode. This type-cast is not
+ valid at the time QSGNode's destructor is called because the node will
+ already be partially destroyed at that point.
+*/
+
+void QSGNode::destroy()
+{
+ if (m_parent) {
+ m_parent->removeChildNode(this);
+ Q_ASSERT(m_parent == 0);
+ }
+ while (m_firstChild) {
+ QSGNode *child = m_firstChild;
+ removeChildNode(child);
+ Q_ASSERT(child->m_parent == 0);
+ if (child->flags() & OwnedByParent)
+ delete child;
+ }
+
+ Q_ASSERT(m_firstChild == 0 && m_lastChild == 0);
+}
+
+
+/*!
+ Prepends \a node to this node's the list of children.
+
+ Ordering of nodes is important as geometry nodes will be rendered in the
+ order they are added to the scene graph.
+ */
+
+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
+
+ if (m_firstChild)
+ m_firstChild->m_previousSibling = node;
+ else
+ m_lastChild = node;
+ node->m_nextSibling = m_firstChild;
+ m_firstChild = node;
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+/*!
+ Appends \a node to this node's list of children.
+
+ Ordering of nodes is important as geometry nodes will be rendered in the
+ order they are added to the scene graph.
+ */
+
+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
+
+ if (m_lastChild)
+ m_lastChild->m_nextSibling = node;
+ else
+ m_firstChild = node;
+ node->m_previousSibling = m_lastChild;
+ m_lastChild = node;
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+
+
+/*!
+ Inserts \a node to this node's list of children before the node specified with \a before.
+
+ Ordering of nodes is important as geometry nodes will be rendered in the
+ order they are added to the scene graph.
+ */
+
+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(before && before->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");
+
+#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
+
+ QSGNode *previous = before->m_previousSibling;
+ if (previous)
+ previous->m_nextSibling = node;
+ else
+ m_firstChild = node;
+ node->m_previousSibling = previous;
+ node->m_nextSibling = before;
+ before->m_previousSibling = node;
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+
+
+/*!
+ Inserts \a node to this node's list of children after the node specified with \a after.
+
+ Ordering of nodes is important as geometry nodes will be rendered in the
+ order they are added to the scene graph.
+ */
+
+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(after && after->m_parent == this, "QSGNode::insertChildNodeBefore", "The parent of \'before\' is wrong");
+
+#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
+
+ QSGNode *next = after->m_nextSibling;
+ if (next)
+ next->m_previousSibling = node;
+ else
+ m_lastChild = node;
+ node->m_nextSibling = next;
+ node->m_previousSibling = after;
+ after->m_nextSibling = node;
+ node->m_parent = this;
+
+ node->markDirty(DirtyNodeAdded);
+}
+
+
+
+/*!
+ Removes \a node from this node's list of children.
+ */
+
+void QSGNode::removeChildNode(QSGNode *node)
+{
+ //Q_ASSERT(m_children.contains(node));
+ Q_ASSERT(node->parent() == this);
+
+ QSGNode *previous = node->m_previousSibling;
+ QSGNode *next = node->m_nextSibling;
+ if (previous)
+ previous->m_nextSibling = next;
+ else
+ m_firstChild = next;
+ if (next)
+ next->m_previousSibling = previous;
+ else
+ m_lastChild = previous;
+ node->m_previousSibling = 0;
+ node->m_nextSibling = 0;
+
+ node->markDirty(DirtyNodeRemoved);
+ node->m_parent = 0;
+}
+
+
+/*!
+ Removes all child nodes from this node's list of children.
+ */
+
+void QSGNode::removeAllChildNodes()
+{
+ while (m_firstChild) {
+ QSGNode *node = m_firstChild;
+ m_firstChild = node->m_nextSibling;
+ node->m_nextSibling = 0;
+ if (m_firstChild)
+ m_firstChild->m_previousSibling = 0;
+ else
+ m_lastChild = 0;
+ node->markDirty(DirtyNodeRemoved);
+ node->m_parent = 0;
+ }
+}
+
+
+int QSGNode::childCount() const
+{
+ int count = 0;
+ QSGNode *n = m_firstChild;
+ while (n) {
+ ++count;
+ n = n->m_nextSibling;
+ }
+ return count;
+}
+
+
+QSGNode *QSGNode::childAtIndex(int i) const
+{
+ QSGNode *n = m_firstChild;
+ while (i && n) {
+ --i;
+ n = n->m_nextSibling;
+ }
+ return n;
+}
+
+
+/*!
+ 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;
+}
+
+
+
+/*!
+ Marks this node with the states in \a flags as dirty.
+
+ When a node is marked dirty, it recursively mark the parent chain
+ as dirty and notify all connected renderers that the has dirty states.
+ */
+
+void QSGNode::markDirty(DirtyFlags flags)
+{
+ m_flags |= (flags & DirtyPropagationMask);
+
+ DirtyFlags subtreeFlags = DirtyFlags((flags & DirtyPropagationMask) << 16);
+
+ int geometryCountDiff = 0;
+ if (flags & DirtyNodeAdded)
+ geometryCountDiff += m_subtreeGeometryCount;
+ if (flags & DirtyNodeRemoved)
+ geometryCountDiff -= m_subtreeGeometryCount;
+
+ QSGNode *p = m_parent;
+ while (p) {
+ p->m_flags |= subtreeFlags;
+ p->m_subtreeGeometryCount += geometryCountDiff;
+ if (p->type() == RootNodeType)
+ static_cast<QSGRootNode *>(p)->notifyNodeChange(this, flags);
+ p = p->m_parent;
+ }
+}
+
+
+
+/*!
+ \class QSGBasicGeometryNode
+ \brief The QSGBasicGeometryNode class serves as a baseclass for geometry based nodes
+
+ \inmodule QtQuick
+
+ The QSGBasicGeometryNode class should not be used by itself. It is only encapsulates
+ shared functionality between the QSGGeometryNode and QSGClipNode classes.
+ */
+
+
+/*!
+ Creates a new basic geometry node.
+ */
+QSGBasicGeometryNode::QSGBasicGeometryNode(NodeType type)
+ : QSGNode(type)
+ , m_geometry(0)
+ , m_matrix(0)
+ , m_clip_list(0)
+{
+}
+
+
+/*!
+ Deletes this QSGBasicGeometryNode.
+
+ If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
+ geometry object it is pointing to. This flag is not set by default.
+ */
+
+QSGBasicGeometryNode::~QSGBasicGeometryNode()
+{
+ if (flags() & OwnsGeometry)
+ delete m_geometry;
+}
+
+
+/*!
+ \fn QSGGeometry *QSGBasicGeometryNode::geometry() const
+
+ Returns this node's geometry.
+
+ The geometry is null by default.
+ */
+
+
+/*!
+ Sets the geometry of this node to \a geometry.
+
+ If the node has the flag QSGNode::OwnsGeometry set, it will also delete the
+ geometry object it is pointing to. This flag is not set by default.
+ */
+
+void QSGBasicGeometryNode::setGeometry(QSGGeometry *geometry)
+{
+ if (flags() & OwnsGeometry)
+ delete m_geometry;
+ m_geometry = geometry;
+ markDirty(DirtyGeometry);
+}
+
+
+
+/*!
+ \class QSGGeometryNode
+ \brief The QSGGeometryNode class is used for all rendered content in the scene graph.
+
+ \inmodule QtQuick
+
+ The QSGGeometryNode consists of geometry and material. The geometry defines the mesh,
+ the vertices and their structure, to be drawn. The Material defines how the shape is
+ filled.
+
+ A geometry node must have both geometry and a normal material before it is added to
+ the scene graph.
+
+ The geometry node supports two types of materials, the opaqueMaterial and the normal
+ material. The opaqueMaterial is used when the accumulated scene graph opacity at the
+ time of rendering is 1. The primary usecase is to special case opaque rendering
+ to avoid an extra operation in the fragment shader can have significant performance
+ impact on embedded graphics chips. The opaque material is optional.
+
+ */
+
+
+/*!
+ Creates a new geometry node without geometry and material.
+ */
+
+QSGGeometryNode::QSGGeometryNode()
+ : QSGBasicGeometryNode(GeometryNodeType)
+ , m_render_order(0)
+ , m_material(0)
+ , m_opaque_material(0)
+ , m_opacity(1)
+{
+}
+
+
+/*!
+ Deletes this geometry node.
+
+ The flags QSGNode::OwnsMaterial, QSGNode::OwnsOpaqueMaterial and
+ QSGNode::OwnsGeometry decides weither the geometry node should also
+ delete the materials and geometry. By default, these flags are disabled.
+ */
+
+QSGGeometryNode::~QSGGeometryNode()
+{
+ if (flags() & OwnsMaterial)
+ delete m_material;
+ if (flags() & OwnsOpaqueMaterial)
+ delete m_opaque_material;
+}
+
+
+
+/*!
+ \fn int QSGGeometryNode::renderOrder() const
+
+ Returns the render order of this geometry node.
+
+ \internal
+ */
+
+
+/*!
+ 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.
+
+ Geometry nodes 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;
+}
+
+
+/*!
+ \class QSGClipNode
+ \brief The QSGClipNode class implements the clipping functionality in the scene graph.
+
+ \inmodule QtQuick
+
+ Clipping applies to the node's subtree and can be nested. Multiple clip nodes will be
+ accumulated by intersecting all their geometries. The accumulation happens
+ as part of the rendering.
+
+ Clip nodes must have a geometry before they can be added to the scene graph.
+
+ Clipping is usually implemented by using the stencil buffer.
+ */
+
+
+
+/*!
+ Creates a new QSGClipNode without a geometry.
+
+ The clip node must have a geometry before it can be added to the
+ scene graph.
+ */
+
+QSGClipNode::QSGClipNode()
+ : QSGBasicGeometryNode(ClipNodeType)
+{
+}
+
+
+
+/*!
+ Deletes this QSGClipNode.
+
+ If the flag QSGNode::OwnsGeometry is set, the geometry will also be
+ deleted.
+ */
+
+QSGClipNode::~QSGClipNode()
+{
+}
+
+
+
+/*!
+ \fn bool QSGClipNode::isRectangular() const
+
+ Returns if this clip node has a rectangular clip.
+ */
+
+
+
+/*!
+ Sets whether this clip node has a rectangular clip to \a rectHint.
+
+ This is an optimization hint which means that the renderer can
+ use scissoring instead of stencil, which is significnatly faster.
+
+ When this hint is and it is applicable, the clip region will be
+ generated from clipRect() rather than geometry().
+ */
+
+void QSGClipNode::setIsRectangular(bool rectHint)
+{
+ m_is_rectangular = rectHint;
+}
+
+
+
+/*!
+ \fn void QSGClipNode::clipRect() const
+
+ Returns the clip rect of this node.
+ */
+
+
+/*!
+ 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;
+}
+
+
+/*!
+ \class QSGTransformNode
+ \brief The QSGTransformNode class implements transformations in the scene graph
+
+ \inmodule QtQuick
+
+ Transformations apply the node's subtree and can be nested. Multiple transform nodes
+ will be accumulated by intersecting all their matrices. The accumulation happens
+ as part of the rendering.
+
+ The transform nodes implement a 4x4 matrix which in theory supports full 3D
+ transformations. However, because the renderer optimizes for 2D use-cases rather
+ than 3D use-cases, rendering a scene with full 3D transformations needs to
+ be done with some care.
+ */
+
+QSGTransformNode::QSGTransformNode()
+ : QSGNode(TransformNodeType)
+{
+}
+
+
+
+/*!
+ Deletes this transform node.
+ */
+
+QSGTransformNode::~QSGTransformNode()
+{
+}
+
+
+
+/*!
+ \fn QMatrix4x4 QSGTransformNode::matrix() const
+
+ Returns this transform node's matrix.
+ */
+
+
+
+/*!
+ Sets this transform node's matrix to \a matrix.
+ */
+
+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;
+}
+
+
+
+/*!
+ \class QSGRootNode
+ \brief The QSGRootNode is the toplevel root of any scene graph.
+
+ The root node is used to attach a scene graph to a renderer.
+
+ \internal
+ */
+
+
+
+/*!
+ \fn QSGRootNode::QSGRootNode()
+
+ Creates a new root node.
+ */
+
+QSGRootNode::QSGRootNode()
+ : QSGNode(RootNodeType)
+{
+}
+
+
+/*!
+ Deletes the root node.
+
+ When a root node is deleted it removes itself from all of renderers
+ that are referencing it.
+ */
+
+QSGRootNode::~QSGRootNode()
+{
+ while (!m_renderers.isEmpty())
+ m_renderers.last()->setRootNode(0);
+ destroy(); // Must call destroy() here because markDirty() casts this to QSGRootNode.
+}
+
+
+
+/*!
+ Called to notify all renderers that \a node has been marked as dirty
+ with \a flags.
+ */
+
+void QSGRootNode::notifyNodeChange(QSGNode *node, DirtyFlags flags)
+{
+ for (int i=0; i<m_renderers.size(); ++i) {
+ m_renderers.at(i)->nodeChanged(node, flags);
+ }
+}
+
+
+
+/*!
+ \class QSGOpacityNode
+ \brief The QSGOpacityNode class is used to change opacity of nodes.
+
+ \inmodule QtQuick
+
+ Opacity applies to its subtree and can be nested. Multiple opacity nodes
+ will be accumulated by multiplying their opacity. The accumulation happens
+ as part of the rendering.
+
+ When nested opacity gets below a certain threshold, the subtree might
+ be marked as blocked, causing isSubtreeBlocked() to return true. This
+ is done for performance reasons.
+
+ */
+
+
+
+/*!
+ Constructs an opacity node with a default opacity of 1.
+
+ Opacity accumulates 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()
+ : QSGNode(OpacityNodeType)
+ , m_opacity(1)
+ , m_combined_opacity(1)
+{
+}
+
+
+
+/*!
+ Deletes the opacity node.
+ */
+
+QSGOpacityNode::~QSGOpacityNode()
+{
+}
+
+
+
+/*!
+ \fn qreal QSGOpacityNode::opacity() const
+
+ Returns this opacity node's opacity.
+ */
+
+
+
+/*!
+ 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);
+}
+
+
+
+/*!
+ \fn qreal QSGOpacityNode::combinedOpacity() const
+
+ Returns this node's accumulated opacity.
+
+ This vaule is calculated during rendering and only stored
+ in the opacity node temporarily.
+
+ \internal
+ */
+
+
+
+/*!
+ 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;
+}
+
+
+
+/*!
+ For performance reasons, we block the subtree when the opacity
+ is below a certain threshold.
+
+ \internal
+ */
+
+bool QSGOpacityNode::isSubtreeBlocked() const
+{
+ return QSGNode::isSubtreeBlocked() || m_opacity < 0.001;
+}
+
+
+/*!
+ \class QSGNodeVisitor
+ \brief The QSGNodeVisitor class is a helper class for traversing the scene graph.
+
+ \internal
+ */
+
+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)
+{
+ for (QSGNode *c = n->firstChild(); c; c = c->nextSibling())
+ visitNode(c);
+}
+
+
+
+#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->sizeOfVertex();
+ 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()
+ << "flags=" << (int) n->flags() << dec
+ << (n->isSubtreeBlocked() ? "*BLOCKED*" : "");
+#ifdef QML_RUNTIME_TESTING
+ d << n->description;
+#endif
+ d << ")";
+ break;
+ }
+ return d;
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h
new file mode 100644
index 0000000000..41c63e27b6
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgnode.h
@@ -0,0 +1,346 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NODE_H
+#define NODE_H
+
+#include "qsggeometry.h"
+#include <QtGui/QMatrix4x4>
+
+#include <float.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+#define QML_RUNTIME_TESTING
+
+class QSGRenderer;
+
+class QSGNode;
+class QSGRootNode;
+class QSGGeometryNode;
+class QSGTransformNode;
+class QSGClipNode;
+
+class Q_QUICK_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,
+ DirtyMaterial = 0x0040,
+ DirtyOpacity = 0x0080,
+ DirtyForceUpdate = 0x0100,
+
+ DirtyPropagationMask = DirtyMatrix
+ | DirtyClipList
+ | DirtyNodeAdded
+ | DirtyOpacity
+ | DirtyForceUpdate
+
+ };
+ 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 removeAllChildNodes();
+ void prependChildNode(QSGNode *node);
+ void appendChildNode(QSGNode *node);
+ void insertChildNodeBefore(QSGNode *node, QSGNode *before);
+ void insertChildNodeAfter(QSGNode *node, QSGNode *after);
+
+ int childCount() const;
+ QSGNode *childAtIndex(int i) const;
+ QSGNode *firstChild() const { return m_firstChild; }
+ QSGNode *lastChild() const { return m_lastChild; }
+ QSGNode *nextSibling() const { return m_nextSibling; }
+ QSGNode* previousSibling() const { return m_previousSibling; }
+
+ inline NodeType type() const { return m_type; }
+
+ void clearDirty() { m_flags = 0; }
+ void markDirty(DirtyFlags flags);
+ DirtyFlags dirtyFlags() const { return m_flags; }
+
+ virtual bool isSubtreeBlocked() const;
+
+ 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:
+ QSGNode(NodeType type);
+
+private:
+ friend class QSGRootNode;
+
+ void init();
+ void destroy();
+
+ QSGNode *m_parent;
+ NodeType m_type;
+ QSGNode *m_firstChild;
+ QSGNode *m_lastChild;
+ QSGNode *m_nextSibling;
+ QSGNode *m_previousSibling;
+ int m_subtreeGeometryCount;
+
+ Flags m_nodeFlags;
+ DirtyFlags m_flags;
+
+ void *m_reserved;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGNode::DirtyFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGNode::Flags)
+
+class Q_QUICK_EXPORT QSGBasicGeometryNode : public QSGNode
+{
+public:
+// enum UsagePattern {
+// Static,
+// Dynamic,
+// Stream
+// };
+// void setUsagePattern(UsagePattern pattern);
+// UsagePattern usagePattern() const { return m_pattern; }
+
+ ~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; }
+
+protected:
+ QSGBasicGeometryNode(NodeType type);
+
+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_QUICK_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;
+
+ 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_QUICK_EXPORT QSGClipNode : public QSGBasicGeometryNode
+{
+public:
+ QSGClipNode();
+ ~QSGClipNode();
+
+ 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_QUICK_EXPORT QSGTransformNode : public QSGNode
+{
+public:
+ QSGTransformNode();
+ ~QSGTransformNode();
+
+ 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_QUICK_EXPORT QSGRootNode : public QSGNode
+{
+public:
+ QSGRootNode();
+ ~QSGRootNode();
+
+private:
+ void notifyNodeChange(QSGNode *node, DirtyFlags flags);
+
+ friend class QSGRenderer;
+ friend class QSGNode;
+ friend class QSGGeometryNode;
+
+ QList<QSGRenderer *> m_renderers;
+};
+
+
+class Q_QUICK_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; }
+
+ bool isSubtreeBlocked() const;
+
+private:
+ qreal m_opacity;
+ qreal m_combined_opacity;
+};
+
+class Q_QUICK_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_QUICK_EXPORT QDebug operator<<(QDebug, const QSGNode *n);
+Q_QUICK_EXPORT QDebug operator<<(QDebug, const QSGGeometryNode *n);
+Q_QUICK_EXPORT QDebug operator<<(QDebug, const QSGTransformNode *n);
+Q_QUICK_EXPORT QDebug operator<<(QDebug, const QSGOpacityNode *n);
+Q_QUICK_EXPORT QDebug operator<<(QDebug, const QSGRootNode *n);
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // NODE_H
diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
new file mode 100644
index 0000000000..a7e5b08dc1
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgnodeupdater_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// #define QSG_UPDATER_DEBUG
+
+QSGNodeUpdater::QSGNodeUpdater()
+ : m_combined_matrix_stack(64)
+ , m_opacity_stack(64)
+ , m_current_clip(0)
+ , m_force_update(0)
+{
+ m_opacity_stack.add(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_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()) {
+ if (!m_combined_matrix_stack.isEmpty()) {
+ t->setCombinedMatrix(*m_combined_matrix_stack.last() * t->matrix());
+ } else {
+ t->setCombinedMatrix(t->matrix());
+ }
+ m_combined_matrix_stack.add(&t->combinedMatrix());
+ } else {
+ if (!m_combined_matrix_stack.isEmpty()) {
+ t->setCombinedMatrix(*m_combined_matrix_stack.last());
+ } else {
+ t->setCombinedMatrix(QMatrix4x4());
+ }
+ }
+}
+
+
+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_combined_matrix_stack.pop_back();
+ }
+
+}
+
+
+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.last();
+ 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.last();
+ g->m_clip_list = m_current_clip;
+ g->setInheritedOpacity(m_opacity_stack.last());
+}
+
+void QSGNodeUpdater::leaveGeometryNode(QSGGeometryNode *g)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "leave geometry" << g;
+#else
+ Q_UNUSED(g)
+#endif
+}
+
+void QSGNodeUpdater::enterOpacityNode(QSGOpacityNode *o)
+{
+ if (o->dirtyFlags() & QSGNode::DirtyOpacity)
+ ++m_force_update;
+
+ qreal opacity = m_opacity_stack.last() * o->opacity();
+ o->setCombinedOpacity(opacity);
+ m_opacity_stack.add(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_back();
+}
+
+void QSGNodeUpdater::visitChildren(QSGNode *n)
+{
+ for (QSGNode *c = n->firstChild(); c; c = c->nextSibling())
+ visitNode(c);
+}
+
+void QSGNodeUpdater::visitNode(QSGNode *n)
+{
+#ifdef QSG_UPDATER_DEBUG
+ qDebug() << "enter:" << n;
+#endif
+
+ if (!n->dirtyFlags() && !m_force_update)
+ return;
+ if (n->isSubtreeBlocked())
+ return;
+
+ bool forceUpdate = n->dirtyFlags() & (QSGNode::DirtyNodeAdded | QSGNode::DirtyForceUpdate);
+ if (forceUpdate)
+ ++m_force_update;
+
+ 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;
+ }
+
+ if (forceUpdate)
+ --m_force_update;
+
+ n->clearDirty();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h b/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h
new file mode 100644
index 0000000000..446bdefdc5
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NODEUPDATER_P_H
+#define NODEUPDATER_P_H
+
+#include "qsgnode.h"
+#include <QtGui/private/qdatabuffer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_EXPORT QSGNodeUpdater
+{
+public:
+ QSGNodeUpdater();
+
+ virtual void updateStates(QSGNode *n);
+ virtual bool isNodeBlocked(QSGNode *n, QSGNode *root) const;
+
+ void setToplevelOpacity(qreal alpha) { m_opacity_stack.last() = alpha; }
+ qreal toplevelOpacity() const { return m_opacity_stack.last(); }
+
+protected:
+ virtual void enterTransformNode(QSGTransformNode *);
+ virtual void leaveTransformNode(QSGTransformNode *);
+ void enterClipNode(QSGClipNode *c);
+ void leaveClipNode(QSGClipNode *c);
+ void enterOpacityNode(QSGOpacityNode *o);
+ void leaveOpacityNode(QSGOpacityNode *o);
+ void enterGeometryNode(QSGGeometryNode *);
+ void leaveGeometryNode(QSGGeometryNode *);
+
+ void visitNode(QSGNode *n);
+ void visitChildren(QSGNode *n);
+
+
+ QDataBuffer<const QMatrix4x4 *> m_combined_matrix_stack;
+ QDataBuffer<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/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
new file mode 100644
index 0000000000..b22631afae
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -0,0 +1,743 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgrenderer_p.h"
+#include "qsgnode.h"
+#include "qsgmaterial.h"
+#include "qsgnodeupdater_p.h"
+#include "qsggeometry_p.h"
+
+#include <private/qsgadaptationlayer_p.h>
+
+#include <QOpenGLShaderProgram>
+#include <qopenglframebufferobject.h>
+#include <QtGui/qguiapplication.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 bool qsg_render_timing = !qgetenv("QML_RENDERER_TIMING").isEmpty();
+static QTime frameTimer;
+static int preprocessTime;
+static int updatePassTime;
+#endif
+
+void QSGBindable::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 QSGBindable::reactivate() const
+{
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+}
+
+QSGBindableFbo::QSGBindableFbo(QOpenGLFramebufferObject *fbo) : m_fbo(fbo)
+{
+}
+
+
+void QSGBindableFbo::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_current_opacity(1)
+ , m_context(context)
+ , m_root_node(0)
+ , m_node_updater(0)
+ , m_bindable(0)
+ , m_changed_emitted(false)
+ , m_mirrored(false)
+ , m_is_rendering(false)
+ , m_vertex_buffer_bound(false)
+ , m_index_buffer_bound(false)
+{
+ 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 QSGBindable
+ {
+ public:
+ void bind() const { QOpenGLFramebufferObject::bindDefault(); }
+ } b;
+ renderScene(b);
+}
+
+void QSGRenderer::renderScene(const QSGBindable &bindable)
+{
+ if (!m_root_node)
+ return;
+
+ m_is_rendering = true;
+
+
+#ifdef QSG_RENDERER_TIMING
+ if (qsg_render_timing)
+ frameTimer.start();
+ int bindTime;
+ int renderTime;
+#endif
+
+ m_bindable = &bindable;
+ preprocess();
+
+ bindable.bind();
+#ifdef QSG_RENDERER_TIMING
+ if (qsg_render_timing)
+ bindTime = frameTimer.elapsed();
+#endif
+
+#ifndef QT_NO_DEBUG
+ // Sanity check that attribute registers are disabled
+ {
+ GLint count;
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &count);
+ GLint enabled;
+ for (int i=0; i<count; ++i) {
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled);
+ if (enabled) {
+ qWarning("QSGRenderer: attribute %d is enabled, this can lead to memory corruption and crashes.", i);
+ }
+ }
+ }
+#endif
+
+ render();
+#ifdef QSG_RENDERER_TIMING
+ if (qsg_render_timing)
+ renderTime = frameTimer.elapsed();
+#endif
+
+ glDisable(GL_SCISSOR_TEST);
+ m_is_rendering = false;
+ m_changed_emitted = false;
+ m_bindable = 0;
+
+ if (m_vertex_buffer_bound) {
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ m_vertex_buffer_bound = false;
+ }
+
+ if (m_index_buffer_bound) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ m_index_buffer_bound = false;
+ }
+
+#ifdef QSG_RENDERER_TIMING
+ if (qsg_render_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::setProjectionMatrixToDeviceRect()
+{
+ setProjectionMatrixToRect(m_device_rect);
+}
+
+void QSGRenderer::setProjectionMatrixToRect(const QRectF &rect)
+{
+ QMatrix4x4 matrix;
+ matrix.ortho(rect.x(),
+ rect.x() + rect.width(),
+ rect.y() + rect.height(),
+ rect.y(),
+ qreal(0.01),
+ -1);
+ setProjectionMatrix(matrix);
+}
+
+void QSGRenderer::setProjectionMatrix(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;
+}
+
+/*!
+ Updates internal data structures and emits the sceneGraphChanged() signal.
+
+ If \a flags contains the QSGNode::DirtyNodeRemoved flag, the node might be
+ in the process of being destroyed. It is then not safe to downcast the node
+ pointer.
+*/
+
+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
+ if (qsg_render_timing)
+ preprocessTime = frameTimer.elapsed();
+#endif
+
+ nodeUpdater()->setToplevelOpacity(context()->renderAlpha());
+ nodeUpdater()->updateStates(m_root_node);
+
+#ifdef QSG_RENDERER_TIMING
+ if (qsg_render_timing)
+ updatePassTime = frameTimer.elapsed();
+#endif
+
+}
+
+void QSGRenderer::addNodesToPreprocess(QSGNode *node)
+{
+ for (QSGNode *c = node->firstChild(); c; c = c->nextSibling())
+ addNodesToPreprocess(c);
+ if (node->flags() & QSGNode::UsePreprocess)
+ m_nodes_to_preprocess.insert(node);
+}
+
+void QSGRenderer::removeNodesToPreprocess(QSGNode *node)
+{
+ for (QSGNode *c = node->firstChild(); c; c = c->nextSibling())
+ removeNodesToPreprocess(c);
+ 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 m = m_current_projection_matrix;
+ if (clip->matrix())
+ m *= *clip->matrix();
+
+ // TODO: Check for multisampling and pixel grid alignment.
+ bool isRectangleWithNoPerspective = clip->isRectangular()
+ && qFuzzyIsNull(m(3, 0)) && qFuzzyIsNull(m(3, 1));
+ bool noRotate = qFuzzyIsNull(m(0, 1)) && qFuzzyIsNull(m(1, 0));
+ bool isRotate90 = qFuzzyIsNull(m(0, 0)) && qFuzzyIsNull(m(1, 1));
+
+ if (isRectangleWithNoPerspective && (noRotate || isRotate90)) {
+ QRectF bbox = clip->clipRect();
+ qreal invW = 1 / m(3, 3);
+ qreal fx1, fy1, fx2, fy2;
+ if (noRotate) {
+ fx1 = (bbox.left() * m(0, 0) + m(0, 3)) * invW;
+ fy1 = (bbox.bottom() * m(1, 1) + m(1, 3)) * invW;
+ fx2 = (bbox.right() * m(0, 0) + m(0, 3)) * invW;
+ fy2 = (bbox.top() * m(1, 1) + m(1, 3)) * invW;
+ } else {
+ Q_ASSERT(isRotate90);
+ fx1 = (bbox.bottom() * m(0, 1) + m(0, 3)) * invW;
+ fy1 = (bbox.left() * m(1, 0) + m(1, 3)) * invW;
+ fx2 = (bbox.top() * m(0, 1) + m(0, 3)) * invW;
+ fy2 = (bbox.right() * m(1, 0) + m(1, 3)) * invW;
+ }
+
+ if (fx1 > fx2)
+ qSwap(fx1, fx2);
+ if (fy1 > fy2)
+ qSwap(fy1, fy2);
+
+ 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);
+ }
+
+ glScissor(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
+ } else {
+ if (!stencilEnabled) {
+ if (!m_clip_program.isLinked()) {
+ m_clip_program.addShaderFromSourceCode(QOpenGLShader::Vertex,
+ "attribute highp vec4 vCoord; \n"
+ "uniform highp mat4 matrix; \n"
+ "void main() { \n"
+ " gl_Position = matrix * vCoord; \n"
+ "}");
+ m_clip_program.addShaderFromSourceCode(QOpenGLShader::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);
+ 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 *g = clip->geometry();
+ Q_ASSERT(g->attributeCount() > 0);
+ const QSGGeometry::Attribute *a = g->attributes();
+ glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, g->sizeOfVertex(), g->vertexData());
+
+ m_clip_program.setUniformValue(m_clip_matrix_id, m);
+ if (g->indexCount()) {
+ glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData());
+ } else {
+ glDrawArrays(g->drawingMode(), 0, g->vertexCount());
+ }
+
+ ++clipDepth;
+ }
+
+ clip = clip->clipList();
+ }
+
+ if (stencilEnabled) {
+ m_clip_program.disableAttributeArray(0);
+ 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();
+ } else {
+ glDisable(GL_STENCIL_TEST);
+ }
+
+ if (!scissorEnabled)
+ glDisable(GL_SCISSOR_TEST);
+
+ return stencilEnabled ? StencilClip : ScissorClip;
+}
+
+
+
+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)
+ };
+ Q_ASSERT(type >= GL_BYTE && type <= 0x140A); // the value of GL_DOUBLE
+ return sizes[type - GL_BYTE];
+}
+
+
+class QSGRendererVBOGeometryData : public QSGGeometryData
+{
+public:
+ QSGRendererVBOGeometryData()
+ : vertexBuffer(0)
+ , indexBuffer(0)
+ {
+ }
+
+ ~QSGRendererVBOGeometryData()
+ {
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (!ctx)
+ return;
+ QOpenGLFunctions *func = ctx->functions();
+ if (vertexBuffer)
+ func->glDeleteBuffers(1, &vertexBuffer);
+ if (indexBuffer)
+ func->glDeleteBuffers(1, &indexBuffer);
+ }
+
+ GLuint vertexBuffer;
+ GLuint indexBuffer;
+
+ static QSGRendererVBOGeometryData *get(const QSGGeometry *g) {
+ QSGRendererVBOGeometryData *gd = static_cast<QSGRendererVBOGeometryData *>(QSGGeometryData::data(g));
+ if (!gd) {
+ gd = new QSGRendererVBOGeometryData;
+ QSGGeometryData::install(g, gd);
+ }
+ return gd;
+ }
+
+};
+
+static inline GLenum qt_drawTypeForPattern(QSGGeometry::DataPattern p)
+{
+ Q_ASSERT(p > 0 && p <= 3);
+ static GLenum drawTypes[] = { 0,
+ GL_STREAM_DRAW,
+ GL_DYNAMIC_DRAW,
+ GL_STATIC_DRAW
+ };
+ return drawTypes[p];
+}
+
+
+/*!
+ Issues the GL draw call for the geometry \a g using the material \a shader.
+
+ The function assumes that attributes have been bound and set up prior
+ to making this call.
+
+ \internal
+ */
+
+void QSGRenderer::draw(const QSGMaterialShader *shader, const QSGGeometry *g)
+{
+ // ### remove before final release...
+ static bool use_vbo = !QGuiApplication::arguments().contains(QLatin1String("--no-vbo"));
+
+ const void *vertexData;
+ int vertexByteSize = g->vertexCount() * g->sizeOfVertex();
+ if (use_vbo && g->vertexDataPattern() != QSGGeometry::AlwaysUploadPattern && vertexByteSize > 1024) {
+
+ // The base pointer for a VBO is 0
+ vertexData = 0;
+
+ bool updateData = QSGGeometryData::hasDirtyVertexData(g);
+ QSGRendererVBOGeometryData *gd = QSGRendererVBOGeometryData::get(g);
+ if (!gd->vertexBuffer) {
+ glGenBuffers(1, &gd->vertexBuffer);
+ updateData = true;
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, gd->vertexBuffer);
+ m_vertex_buffer_bound = true;
+
+ if (updateData) {
+ glBufferData(GL_ARRAY_BUFFER, vertexByteSize, g->vertexData(),
+ qt_drawTypeForPattern(g->vertexDataPattern()));
+ QSGGeometryData::clearDirtyVertexData(g);
+ }
+
+ } else {
+ if (m_vertex_buffer_bound) {
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ m_vertex_buffer_bound = false;
+ }
+ vertexData = g->vertexData();
+ }
+
+ // Bind the vertices to attributes...
+ char const *const *attrNames = shader->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->sizeOfVertex(), (char *) vertexData + offset);
+ offset += a.tupleSize * size_of_type(a.type);
+ }
+
+ // Set up the indices...
+ const void *indexData;
+ if (use_vbo && g->indexDataPattern() != QSGGeometry::AlwaysUploadPattern && g->indexCount() > 512) {
+
+ // Base pointer for a VBO is 0
+ indexData = 0;
+
+ bool updateData = QSGGeometryData::hasDirtyIndexData(g);
+ QSGRendererVBOGeometryData *gd = QSGRendererVBOGeometryData::get(g);
+ if (!gd->indexBuffer) {
+ glGenBuffers(1, &gd->indexBuffer);
+ updateData = true;
+ }
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gd->indexBuffer);
+ m_index_buffer_bound = true;
+
+ if (updateData) {
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+ g->indexCount() * g->sizeOfIndex(),
+ g->indexData(),
+ qt_drawTypeForPattern(g->indexDataPattern()));
+ QSGGeometryData::clearDirtyIndexData(g);
+ }
+
+ } else {
+ if (m_index_buffer_bound) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ m_index_buffer_bound = false;
+ }
+ indexData = g->indexData();
+ }
+
+
+ // draw the stuff...
+ if (g->indexCount()) {
+ glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), indexData);
+ } else {
+ glDrawArrays(g->drawingMode(), 0, g->vertexCount());
+ }
+
+ // We leave buffers bound for now... They will be reset by bind on next draw() or
+ // set back to 0 if next draw is not using VBOs
+
+}
+
+/*!
+ \class QSGNodeDumper
+ \brief The QSGNodeDumper class provides a way of dumping a scene grahp to the console.
+
+ This class is solely for debugging purposes.
+
+ \internal
+ */
+
+void QSGNodeDumper::dump(QSGNode *n)
+{
+ QSGNodeDumper dump;
+ dump.visitNode(n);
+}
+
+void QSGNodeDumper::visitNode(QSGNode *n)
+{
+ qDebug() << QString(m_indent * 2, QLatin1Char(' ')) << n;
+ QSGNodeVisitor::visitNode(n);
+}
+
+void QSGNodeDumper::visitChildren(QSGNode *n)
+{
+ ++m_indent;
+ QSGNodeVisitor::visitChildren(n);
+ --m_indent;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
new file mode 100644
index 0000000000..e5667c710a
--- /dev/null
+++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include <qset.h>
+#include <qhash.h>
+
+#include <qcolor.h>
+#include <qopenglfunctions.h>
+#include <qopenglshaderprogram.h>
+
+#include "qsgnode.h"
+#include "qsgmaterial.h"
+#include <QtQuick/qsgtexture.h>
+
+#include <QtQuick/private/qsgcontext_p.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QSGMaterialShader;
+struct QSGMaterialType;
+class QOpenGLFramebufferObject;
+class TextureReference;
+class QSGBindable;
+class QSGNodeUpdater;
+
+class Q_QUICK_EXPORT QSGRenderer : public QObject, public QOpenGLFunctions
+{
+ 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; }
+
+ // Accessed by QSGMaterialShader::RenderState.
+ QMatrix4x4 currentProjectionMatrix() const { return m_current_projection_matrix; }
+ QMatrix4x4 currentModelViewMatrix() const { return m_current_model_view_matrix; }
+ QMatrix4x4 currentCombinedMatrix() const { return m_current_projection_matrix * m_current_model_view_matrix; }
+ qreal currentOpacity() const { return m_current_opacity; }
+
+ void setProjectionMatrixToDeviceRect();
+ void setProjectionMatrixToRect(const QRectF &rect);
+ void setProjectionMatrix(const QMatrix4x4 &matrix);
+ QMatrix4x4 projectionMatrix() const { return m_projection_matrix; }
+ bool isMirrored() const { return m_mirrored; }
+
+ void setClearColor(const QColor &color);
+ QColor clearColor() const { return m_clear_color; }
+
+ QOpenGLContext *glContext() const { Q_ASSERT(m_context); return m_context->glContext(); }
+
+ QSGContext *context();
+
+ void renderScene();
+ void renderScene(const QSGBindable &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 QSGMaterialShader *material, const QSGGeometry *g);
+
+ virtual void render() = 0;
+ QSGRenderer::ClipType updateStencilClip(const QSGClipNode *clip);
+
+ const QSGBindable *bindable() const { return m_bindable; }
+
+ virtual void preprocess();
+
+ void addNodesToPreprocess(QSGNode *node);
+ void removeNodesToPreprocess(QSGNode *node);
+
+
+ QColor m_clear_color;
+ ClearMode m_clear_mode;
+ QMatrix4x4 m_current_projection_matrix;
+ QMatrix4x4 m_current_model_view_matrix;
+ qreal m_current_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;
+ QOpenGLShaderProgram m_clip_program;
+ int m_clip_matrix_id;
+
+ const QSGBindable *m_bindable;
+
+ uint m_changed_emitted : 1;
+ uint m_mirrored : 1;
+ uint m_is_rendering : 1;
+
+ uint m_vertex_buffer_bound : 1;
+ uint m_index_buffer_bound : 1;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSGRenderer::ClearMode)
+
+class Q_QUICK_EXPORT QSGBindable
+{
+public:
+ virtual ~QSGBindable() { }
+ virtual void bind() const = 0;
+ virtual void clear(QSGRenderer::ClearMode mode) const;
+ virtual void reactivate() const;
+};
+
+class QSGBindableFbo : public QSGBindable
+{
+public:
+ QSGBindableFbo(QOpenGLFramebufferObject *fbo);
+ virtual void bind() const;
+private:
+ QOpenGLFramebufferObject *m_fbo;
+};
+
+
+
+QSGMaterialShader::RenderState QSGRenderer::state(QSGMaterialShader::RenderState::DirtyStates dirty) const
+{
+ QSGMaterialShader::RenderState s;
+ s.m_dirty = dirty;
+ s.m_data = this;
+ return s;
+}
+
+
+class Q_QUICK_EXPORT 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;
+};
+
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // RENDERER_H