aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/coreapi
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2011-11-23 15:14:07 +0100
committerQt by Nokia <qt-info@nokia.com>2011-12-02 14:18:20 +0100
commit6c8378eaf1edbbefe6aaa3672b0127816a004fd7 (patch)
tree8ee08fb447e052f7a7a685fbeaaa04f04ea60126 /src/quick/scenegraph/coreapi
parente01219b77b1e889e70437635905d7ff820568e23 (diff)
Say hello to QtQuick module
This change moves the QtQuick 2 types and C++ API (including SceneGraph) to a new module (AKA library), QtQuick. 99% of this change is moving files from src/declarative to src/quick, and from tests/auto/declarative to tests/auto/qtquick2. The loading of QtQuick 2 ("import QtQuick 2.0") is now delegated to a plugin, src/imports/qtquick2, just like it's done for QtQuick 1. All tools, examples, and tests that use QtQuick C++ API have gotten "QT += quick" or "QT += quick-private" added to their .pro file. A few additional internal QtDeclarative classes had to be exported (via Q_DECLARATIVE_PRIVATE_EXPORT) since they're needed by the QtQuick 2 implementation. The old header locations (e.g. QtDeclarative/qquickitem.h) will still be supported for some time, but will produce compile-time warnings. (To avoid the QtQuick implementation using the compatibility headers (since QtDeclarative's includepath comes first), a few include statements were modified, e.g. from "#include <qsgnode.h>" to "#include <QtQuick/qsgnode.h>".) There's a change in qtbase that automatically adds QtQuick to the module list if QtDeclarative is used. Together with the compatibility headers, this should help reduce the migration pain for existing projects. In theory, simply getting an existing QtDeclarative-based project to compile and link shouldn't require any changes for now -- but porting to the new scheme is of course recommended, and will eventually become mandatory. Task-number: QTBUG-22889 Reviewed-by: Lars Knoll <lars.knoll@nokia.com> Change-Id: Ia52be9373172ba2f37e7623231ecb060316c96a7 Reviewed-by: Kent Hansen <kent.hansen@nokia.com> Reviewed-by: Sergio Ahumada <sergio.ahumada@nokia.com>
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