summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@nokia.com>2010-11-19 15:11:43 +0100
committerGunnar Sletta <gunnar.sletta@nokia.com>2010-11-19 15:11:43 +0100
commit600e0e08c20255e674b1102aa4d2d1c6ef49091d (patch)
treed64a79cfd1ccb669041f7179d3e383255beca6c0
parentb330749f1eb915db5493a3b1bbc1420c64868307 (diff)
parent651bed285a79ba2d541d061abb641ad074607b79 (diff)
Merge branch 'master' of scm.dev.nokia.troll.no:research/qt-scene-graph
-rw-r--r--README5
-rw-r--r--examples/shadereffectitem/Effectoids/Box4PointBlur.qml11
-rw-r--r--examples/shadereffectitem/Effectoids/Colorize.qml6
-rw-r--r--examples/shadereffectitem/Effectoids/Directional4PointBlur.qml11
-rw-r--r--examples/shadereffectitem/Effectoids/Directional8PointBlur.qml20
-rw-r--r--examples/shadereffectitem/Effectoids/DropShadow.qml13
-rw-r--r--plugins/plugins.pro2
-rw-r--r--src/canvas/qvsyncanimationdriver.cpp18
-rw-r--r--src/canvas/qxclipnode.cpp87
-rw-r--r--src/canvas/qxclipnode_p.h6
-rw-r--r--src/canvas/qxgraphicsview.cpp7
-rw-r--r--src/effects/shadereffectitem.cpp344
-rw-r--r--src/effects/shadereffectitem.h34
-rw-r--r--src/graphicsitems/qxitem.cpp34
-rw-r--r--src/graphicsitems/qxitem.h10
-rw-r--r--src/graphicsitems/qxrectangle.cpp6
-rw-r--r--src/scenegraph/convenience/effectnode.cpp87
-rw-r--r--src/scenegraph/convenience/effectnode.h21
-rw-r--r--src/scenegraph/coreapi/geometry.cpp158
-rw-r--r--src/scenegraph/coreapi/geometry.h54
-rw-r--r--src/scenegraph/coreapi/material.h5
-rw-r--r--src/scenegraph/coreapi/node.cpp4
-rw-r--r--src/scenegraph/coreapi/node.h11
-rw-r--r--src/scenegraph/coreapi/qmlrenderer.cpp99
-rw-r--r--src/scenegraph/coreapi/qmlrenderer.h8
-rw-r--r--src/scenegraph/coreapi/renderer.cpp128
-rw-r--r--src/scenegraph/coreapi/renderer.h41
-rw-r--r--src/scenegraph_include.pri4
-rw-r--r--tests/ColorizeEffectItem.qml3
-rw-r--r--tests/DirectionalBlurEffectItem.qml1
-rw-r--r--tests/MaskEffectItem.qml47
-rw-r--r--tests/big-flickable.qml20
-rw-r--r--tests/colorizeeffect.qml6
-rw-r--r--tests/rrClip.qml15
-rw-r--r--tools/qmlscene/main.cpp26
35 files changed, 749 insertions, 603 deletions
diff --git a/README b/README
index 05d2aa6..acb96a9 100644
--- a/README
+++ b/README
@@ -15,3 +15,8 @@ Running Stuff:
Using in your own application
- Including the "src/scenegraph_include.pri" file in your own projects should be sufficient.
+
+Notes:
+ - If you are combining scenegraph with qt-lighthouse, the code assumes that the
+ platform plugin provides a single GL fullscreen window, like the EglFS plugin
+ does.
diff --git a/examples/shadereffectitem/Effectoids/Box4PointBlur.qml b/examples/shadereffectitem/Effectoids/Box4PointBlur.qml
index 9e24b6b..f64fbe7 100644
--- a/examples/shadereffectitem/Effectoids/Box4PointBlur.qml
+++ b/examples/shadereffectitem/Effectoids/Box4PointBlur.qml
@@ -48,12 +48,12 @@ ShaderEffectItem
"varying highp vec2 my_TexCoord2; \n" +
"varying highp vec2 my_TexCoord3; \n" +
"varying highp vec2 my_TexCoord4; \n" +
- "uniform sampler2D qt_Texture; \n" +
+ "uniform sampler2D source; \n" +
"void main() { \n" +
- " gl_FragColor = (texture2D(qt_Texture, qt_TexCoord) \n" +
- " + texture2D(qt_Texture, my_TexCoord2) \n" +
- " + texture2D(qt_Texture, my_TexCoord3) \n" +
- " + texture2D(qt_Texture, my_TexCoord4)) * 0.25; \n" +
+ " gl_FragColor = (texture2D(source, qt_TexCoord) \n" +
+ " + texture2D(source, my_TexCoord2) \n" +
+ " + texture2D(source, my_TexCoord3) \n" +
+ " + texture2D(source, my_TexCoord4)) * 0.25; \n" +
"}"
vertexShader:
@@ -76,6 +76,7 @@ ShaderEffectItem
" gl_Position = qt_Matrix * qt_VertexPosition; \n" +
"}"
+ property variant source;
property real xOffset: 0.5 / width
property real yOffset: 0.5 / height
active: true
diff --git a/examples/shadereffectitem/Effectoids/Colorize.qml b/examples/shadereffectitem/Effectoids/Colorize.qml
index 73e3858..4d6ad53 100644
--- a/examples/shadereffectitem/Effectoids/Colorize.qml
+++ b/examples/shadereffectitem/Effectoids/Colorize.qml
@@ -45,11 +45,11 @@ ShaderEffectItem
{
fragmentShader:
"varying highp vec2 qt_TexCoord; \n" +
- "uniform sampler2D qt_Texture; \n" +
+ "uniform sampler2D source; \n" +
"uniform lowp vec4 color; \n" +
"uniform lowp float intensity; \n" +
"void main() { \n" +
- " lowp vec4 pix = texture2D(qt_Texture, qt_TexCoord); \n" +
+ " lowp vec4 pix = texture2D(source, qt_TexCoord); \n" +
" lowp float gray = dot(pix.rgb, vec3(0.5, 0.5, 0.5)); \n" +
" gl_FragColor = mix(pix, color * (gray * pix.w), intensity); \n" +
"}"
@@ -64,6 +64,8 @@ ShaderEffectItem
" gl_Position = qt_Matrix * qt_VertexPosition; \n" +
"}"
+ property variant source;
+
property color color;
property real intensity;
active: intensity > 0
diff --git a/examples/shadereffectitem/Effectoids/Directional4PointBlur.qml b/examples/shadereffectitem/Effectoids/Directional4PointBlur.qml
index 1d7f74d..d5ab6f9 100644
--- a/examples/shadereffectitem/Effectoids/Directional4PointBlur.qml
+++ b/examples/shadereffectitem/Effectoids/Directional4PointBlur.qml
@@ -48,12 +48,12 @@ ShaderEffectItem
"varying highp vec2 qt_TexCoord2; \n" +
"varying highp vec2 qt_TexCoord3; \n" +
"varying highp vec2 qt_TexCoord4; \n" +
- "uniform sampler2D qt_Texture; \n" +
+ "uniform sampler2D source; \n" +
"void main() { \n" +
- " gl_FragColor = ( 2. / 6. * texture2D(qt_Texture, qt_TexCoord) \n" +
- " + 1. / 6. * texture2D(qt_Texture, qt_TexCoord2) \n" +
- " + 2. / 6. * texture2D(qt_Texture, qt_TexCoord3) \n" +
- " + 1. / 6. * texture2D(qt_Texture, qt_TexCoord4)); \n" +
+ " gl_FragColor = ( 2. / 6. * texture2D(source, qt_TexCoord) \n" +
+ " + 1. / 6. * texture2D(source, qt_TexCoord2) \n" +
+ " + 2. / 6. * texture2D(source, qt_TexCoord3) \n" +
+ " + 1. / 6. * texture2D(source, qt_TexCoord4)); \n" +
"}"
vertexShader:
@@ -77,6 +77,7 @@ ShaderEffectItem
"}"
+ property variant source;
property real spread: 1;
property real xStep: 0 / width;
property real yStep: 1 / height;
diff --git a/examples/shadereffectitem/Effectoids/Directional8PointBlur.qml b/examples/shadereffectitem/Effectoids/Directional8PointBlur.qml
index cc4e3b0..3aaaa18 100644
--- a/examples/shadereffectitem/Effectoids/Directional8PointBlur.qml
+++ b/examples/shadereffectitem/Effectoids/Directional8PointBlur.qml
@@ -52,17 +52,17 @@ ShaderEffectItem
"varying highp vec2 qt_TexCoord6; \n" +
"varying highp vec2 qt_TexCoord7; \n" +
"varying highp vec2 qt_TexCoord8; \n" +
- "uniform sampler2D qt_Texture; \n" +
+ "uniform sampler2D source; \n" +
"void main() { \n" +
" gl_FragColor = \n" +
- " (4. / 20. * texture2D(qt_Texture, qt_TexCoord) \n" +
- " + 3. / 20. * texture2D(qt_Texture, qt_TexCoord2) \n" +
- " + 2. / 20. * texture2D(qt_Texture, qt_TexCoord3) \n" +
- " + 1. / 20. * texture2D(qt_Texture, qt_TexCoord4) \n" +
- " + 4. / 20. * texture2D(qt_Texture, qt_TexCoord5) \n" +
- " + 3. / 20. * texture2D(qt_Texture, qt_TexCoord6) \n" +
- " + 2. / 20. * texture2D(qt_Texture, qt_TexCoord7) \n" +
- " + 1. / 20. * texture2D(qt_Texture, qt_TexCoord8)); \n" +
+ " (4. / 20. * texture2D(source, qt_TexCoord) \n" +
+ " + 3. / 20. * texture2D(source, qt_TexCoord2) \n" +
+ " + 2. / 20. * texture2D(source, qt_TexCoord3) \n" +
+ " + 1. / 20. * texture2D(source, qt_TexCoord4) \n" +
+ " + 4. / 20. * texture2D(source, qt_TexCoord5) \n" +
+ " + 3. / 20. * texture2D(source, qt_TexCoord6) \n" +
+ " + 2. / 20. * texture2D(source, qt_TexCoord7) \n" +
+ " + 1. / 20. * texture2D(source, qt_TexCoord8)); \n" +
"}"
vertexShader:
@@ -93,7 +93,7 @@ ShaderEffectItem
" gl_Position = qt_Matrix * qt_VertexPosition; \n" +
"}"
-
+ property variant source;
property real spread: 1;
property real xStep: 0 / width;
property real yStep: 1 / height;
diff --git a/examples/shadereffectitem/Effectoids/DropShadow.qml b/examples/shadereffectitem/Effectoids/DropShadow.qml
index 89f68c8..b28a6ef 100644
--- a/examples/shadereffectitem/Effectoids/DropShadow.qml
+++ b/examples/shadereffectitem/Effectoids/DropShadow.qml
@@ -49,13 +49,13 @@ ShaderEffectItem
"varying highp vec2 my_TexCoord2; \n" +
"varying highp vec2 my_TexCoord3; \n" +
"varying highp vec2 my_TexCoord4; \n" +
- "uniform sampler2D qt_Texture; \n" +
+ "uniform sampler2D source; \n" +
"void main() { \n" +
- " lowp vec4 pix = texture2D(qt_Texture, qt_TexCoord); \n" +
- " lowp float shadow = (texture2D(qt_Texture, my_TexCoord1).w \n" +
- " + texture2D(qt_Texture, my_TexCoord2).w \n" +
- " + texture2D(qt_Texture, my_TexCoord3).w \n" +
- " + texture2D(qt_Texture, my_TexCoord4).w) * 0.1; \n" +
+ " lowp vec4 pix = texture2D(source, qt_TexCoord); \n" +
+ " lowp float shadow = (texture2D(source, my_TexCoord1).w \n" +
+ " + texture2D(source, my_TexCoord2).w \n" +
+ " + texture2D(source, my_TexCoord3).w \n" +
+ " + texture2D(source, my_TexCoord4).w) * 0.1; \n" +
" gl_FragColor = mix(vec4(0, 0, 0, shadow), pix, pix.w); \n" +
"}"
@@ -84,6 +84,7 @@ ShaderEffectItem
" gl_Position = qt_Matrix * qt_VertexPosition; \n" +
"}"
+ property variant source;
property real xOffset: 0.66 / width;
property real yOffset: 0.66 / height;
property real xDisplacement: 10 / width;
diff --git a/plugins/plugins.pro b/plugins/plugins.pro
index c2e4869..66bca21 100644
--- a/plugins/plugins.pro
+++ b/plugins/plugins.pro
@@ -1,2 +1,2 @@
TEMPLATE = subdirs
-SUBDIRS += phononvideo
+contains(QT_CONFIG, phonon):SUBDIRS += phononvideo
diff --git a/src/canvas/qvsyncanimationdriver.cpp b/src/canvas/qvsyncanimationdriver.cpp
index 9ba23f1..dd84dd3 100644
--- a/src/canvas/qvsyncanimationdriver.cpp
+++ b/src/canvas/qvsyncanimationdriver.cpp
@@ -6,6 +6,10 @@
#include <QtGui/qwidget.h>
#include <QtGui/qapplication.h>
+#ifdef Q_WS_QPA
+#include <qplatformglcontext_qpa.h>
+#endif
+
#include <qdebug.h>
class QVSyncAnimationDriverPrivate : public QAnimationDriverPrivate
@@ -65,9 +69,16 @@ bool QVSyncAnimationDriver::event(QEvent *e)
if (e->type() == QEvent::User + 1) {
while (isRunning() && !d->aborted) {
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
QApplication::processEvents(QEventLoop::AllEvents, 1);
advance();
((WidgetAccessor *) d->window)->paint();
+
+#ifdef Q_WS_QPA
+ QPlatformGLContext *ctx = d->window->platformWindow()->glContext();
+ ctx->swapBuffers();
+#endif
+
}
}
@@ -78,6 +89,13 @@ bool QVSyncAnimationDriver::eventFilter(QObject *object, QEvent *event) {
Q_D(QVSyncAnimationDriver);
if (isRunning()) {
+
+#ifdef Q_WS_QPA
+ if (object == d->window && event->type() == QEvent::UpdateRequest)
+ return true;
+ else
+#endif
+
if (object == QApplication::instance() && event->type() == QEvent::Quit) {
// If we get a close event while running, we are actually inside the processEvents()
// block and need to exit an extra level to exit the final exec().
diff --git a/src/canvas/qxclipnode.cpp b/src/canvas/qxclipnode.cpp
index a954b62..aded473 100644
--- a/src/canvas/qxclipnode.cpp
+++ b/src/canvas/qxclipnode.cpp
@@ -44,83 +44,80 @@
#include "qxclipnode_p.h"
#include "utilities.h"
+#include <QtGui/QVector2D>
#include <QtCore/qmath.h>
QxClipNode::QxClipNode(const QRectF &rect)
: m_rect(rect), m_radius(0)
{
- updateGeometry();
+ updateGeometryDescription(Utilities::getRectGeometryDescription(), GL_UNSIGNED_SHORT);
+ Utilities::setupRectGeometry(geometry(), m_rect);
setFlag(ClipIsRectangular, true);
}
void QxClipNode::setRect(const QRectF &rect)
{
m_rect = rect;
- updateGeometry();
+ setUpdateFlag(UpdateGeometry);
}
void QxClipNode::setRadius(qreal radius)
{
m_radius = radius;
- updateGeometry();
+ setUpdateFlag(UpdateGeometry);
setFlag(ClipIsRectangular, radius == 0);
}
+void QxClipNode::update(uint updateFlags)
+{
+ if (updateFlags & UpdateGeometry)
+ updateGeometry();
+}
+
void QxClipNode::updateGeometry()
{
if (qFuzzyIsNull(m_radius)) {
updateGeometryDescription(Utilities::getRectGeometryDescription(), GL_UNSIGNED_SHORT);
Utilities::setupRectGeometry(geometry(), m_rect);
} else {
- // ### Fix.
- updateGeometryDescription(Utilities::getRectGeometryDescription(), GL_UNSIGNED_SHORT);
- Utilities::setupRectGeometry(geometry(), m_rect);
- /*
- //XXX copy of what is in QxRectangle (we should reuse the geometry generated there if possible)
+ struct Vertex
+ {
+ QVector2D position;
+ };
+
+ Geometry *g = geometry();
+ int vertexCount = 0;
+
QRectF rect = m_rect;
- qreal radius = m_radius;
-
- QArray<QVector2D> vertices;
- QGLVertexBuffer v;
-
- qreal zero = 0. * M_PI/180.;
- qreal ninety = 90. * M_PI/180.;
- qreal oneeighty = 180. * M_PI/180.;
- qreal twoseventy = 270. * M_PI/180.;
- qreal nninety = -90. * M_PI/180.;
- qreal step = -1.5708/radius;
-
- //upper left
- QPointF cp(rect.x() + radius, rect.y() + radius);
- for (qreal angle = twoseventy; angle >= oneeighty; angle += step) {
- vertices.append(QVector2D(cp.x() + qFastSin(angle) * radius, cp.y() + qFastCos(angle) * radius));
- }
+ rect.adjust(m_radius, m_radius, -m_radius, -m_radius);
- //upper right
- cp = QPointF(rect.x() + rect.width() - radius, rect.y() + radius);
- for (qreal angle = oneeighty; angle >= ninety; angle += step) {
- vertices.append(QVector2D(cp.x() + qFastSin(angle) * radius, cp.y() + qFastCos(angle) * radius));
- }
+ int segments = qMin(15, qCeil(m_radius)); // Number of segments per corner.
- //lower right
- cp = QPointF(rect.x() + rect.width() - radius, rect.y() + rect.height() - radius);
- for (qreal angle = ninety; angle >= zero; angle += step) {
- vertices.append(QVector2D(cp.x() + qFastSin(angle) * radius, cp.y() + qFastCos(angle) * radius));
- }
+ // Overestimate the number of vertices and indices, reduce afterwards when the actual numbers are known.
+ g->setVertexCount((segments + 1) * 4);
+ g->setIndexCount(0);
+
+ Vertex *vertices = (Vertex *)g->vertexData();
+
+ for (int part = 0; part < 2; ++part) {
+ for (int i = 0; i <= segments; ++i) {
+ //### Should change to calculate sin/cos only once.
+ qreal angle = qreal(0.5 * M_PI) * (part + i / qreal(segments));
+ qreal s = qFastSin(angle);
+ qreal c = qFastCos(angle);
+ qreal y = (part ? rect.bottom() : rect.top()) - m_radius * c; // current inner y-coordinate.
+ qreal lx = rect.left() - m_radius * s; // current inner left x-coordinate.
+ qreal rx = rect.right() + m_radius * s; // current inner right x-coordinate.
- //lower left
- cp = QPointF(rect.x() + radius, rect.y() + rect.height() - radius);
- for (qreal angle = zero; angle >= nninety; angle += step) {
- vertices.append(QVector2D(cp.x() + qFastSin(angle) * radius, cp.y() + qFastCos(angle) * radius));
+ vertices[vertexCount++].position = QVector2D(rx, y);
+ vertices[vertexCount++].position = QVector2D(lx, y);
+ }
}
- vertices.append(QVector2D(rect.x(), rect.y() + radius));
- v.addAttribute(QGL::Position, vertices);
+ g->setDrawingMode(QGL::TriangleStrip);
+ g->setVertexCount(vertexCount);
- setDrawingMode(QGL::TriangleFan);
- setVertexBuffer(v);
- setIndexBuffer(Utilities::createIndexBuffer(vertices.count()));
- */
+ markDirty(DirtyGeometry);
}
setBoundingRect(m_rect);
}
diff --git a/src/canvas/qxclipnode_p.h b/src/canvas/qxclipnode_p.h
index 76d7bbf..0754897 100644
--- a/src/canvas/qxclipnode_p.h
+++ b/src/canvas/qxclipnode_p.h
@@ -49,6 +49,10 @@
class QxClipNode : public ClipNode
{
public:
+ enum UpdateFlag {
+ UpdateGeometry = 1
+ };
+
QxClipNode(const QRectF &);
void setRect(const QRectF &);
@@ -57,6 +61,8 @@ public:
void setRadius(qreal radius);
qreal radius() const { return m_radius; }
+ virtual void update(uint updateFlags);
+
private:
void updateGeometry();
QRectF m_rect;
diff --git a/src/canvas/qxgraphicsview.cpp b/src/canvas/qxgraphicsview.cpp
index 95caa47..20a4fb8 100644
--- a/src/canvas/qxgraphicsview.cpp
+++ b/src/canvas/qxgraphicsview.cpp
@@ -164,7 +164,12 @@ QxGraphicsView::QxGraphicsView(QWidget *parent)
qt_scenegraph_configure_engine(&d->engine);
d->animationDriver.setWidget(this);
- d->animationDriver.install();
+
+ // ### Eventually kick out...
+ if (!qApp->arguments().contains("--no-vsync-animations"))
+ d->animationDriver.install();
+ else
+ printf("Not using VSync Animation Driver\n");
}
QxGraphicsView::~QxGraphicsView()
diff --git a/src/effects/shadereffectitem.cpp b/src/effects/shadereffectitem.cpp
index 996604a..4b85c93 100644
--- a/src/effects/shadereffectitem.cpp
+++ b/src/effects/shadereffectitem.cpp
@@ -48,6 +48,9 @@
#include "adaptationlayer.h"
+#include <QtCore/qsignalmapper.h>
+
+
static const char qt_default_vertex_code[] =
"uniform highp mat4 qt_Matrix; \n"
"attribute highp vec4 qt_Vertex; \n"
@@ -96,8 +99,8 @@ void CustomShaderMaterialData::deactivate()
void CustomShaderMaterialData::updateRendererState(Renderer *renderer, Renderer::Updates updates)
{
- if ((updates & Renderer::UpdateMatrices) && !q->m_matrixName.isEmpty())
- q->m_program.setUniformValue(q->m_matrixName.constData(), renderer->combinedMatrix());
+ if ((updates & Renderer::UpdateMatrices) && q->m_respects_matrix)
+ q->m_program.setUniformValue("qt_Matrix", renderer->combinedMatrix());
}
void CustomShaderMaterialData::updateEffectState(Renderer *, AbstractEffect *newEffect, AbstractEffect *oldEffect)
@@ -108,21 +111,15 @@ void CustomShaderMaterialData::updateEffectState(Renderer *, AbstractEffect *new
Q_UNUSED(newEffect);
GLint filtering = q->m_linear_filtering ? GL_LINEAR : GL_NEAREST;
- if (q->m_mask) {
- qt_gl_ActiveTexture(GL_TEXTURE0 + EffectSubtreeNode::Mask);
-#if !defined(QT_OPENGL_ES_2)
- glEnable(GL_TEXTURE_2D);
-#endif
- q->m_texture[EffectSubtreeNode::Mask]->bind();
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
- }
- if (q->m_source) {
- qt_gl_ActiveTexture(GL_TEXTURE0 + EffectSubtreeNode::Source);
+ for (int i = q->m_sources.size() - 1; i >= 0; --i) {
+ qt_gl_ActiveTexture(GL_TEXTURE0 + i);
#if !defined(QT_OPENGL_ES_2)
glEnable(GL_TEXTURE_2D);
#endif
- q->m_texture[EffectSubtreeNode::Source]->bind();
+ if (q->m_sources.at(i).texture.isNull())
+ glBindTexture(GL_TEXTURE_2D, 0);
+ else
+ q->m_sources.at(i).texture->bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
}
@@ -148,8 +145,28 @@ void CustomShaderMaterialData::updateEffectState(Renderer *, AbstractEffect *new
case QVariant::Int:
q->m_program.setUniformValue(name.constData(), v.toInt());
break;
+ case QVariant::Size:
+ case QVariant::SizeF:
+ q->m_program.setUniformValue(name.constData(), v.toSizeF());
+ break;
+ case QVariant::Point:
+ case QVariant::PointF:
+ q->m_program.setUniformValue(name.constData(), v.toPointF());
+ break;
+ case QVariant::Rect:
+ case QVariant::RectF:
+ {
+ QRectF r = v.toRectF();
+ q->m_program.setUniformValue(name.constData(), r.x(), r.y(), r.width(), r.height());
+ }
+ break;
+ case QVariant::Vector3D:
+ q->m_program.setUniformValue(name.constData(), qvariant_cast<QVector3D>(v));
+ break;
default:
- qWarning("ShaderEffectItem: unhandled uniform value for '%s': type=%d, typeName=%s\n", name.constData(), v.type(), v.typeName());
+ // QObjects are probably mapped to sampler2Ds which are handled above.
+ if (!qVariantCanConvert<QObject *>(v))
+ qWarning("ShaderEffectItem: unhandled uniform value for '%s': type=%d, typeName=%s\n", name.constData(), v.type(), v.typeName());
break;
}
}
@@ -165,25 +182,30 @@ const QGL::VertexAttribute *CustomShaderMaterialData::requiredFields() const
ShaderEffectItem::ShaderEffectItem(QxItem *parent)
: QxItem(parent)
- , m_source(0)
- , m_mask(0)
, m_data(0)
, m_mesh_resolution(1, 1)
, m_linear_filtering(false)
, m_program_dirty(true)
, m_geometry_dirty(true)
, m_active(true)
+ , m_respects_matrix(false)
, m_respects_opacity(false)
{
setFlags(Blending);
- qMemSet(m_effectDepth, 0, sizeof(m_effectDepth));
m_node.setMaterial(this);
m_node.updateGeometryDescription(Utilities::getTexturedRectGeometryDescription(), GL_UNSIGNED_SHORT);
Utilities::setupRectGeometry(m_node.geometry(), QRectF(0, 0, 1, 1), QSize(1, 1), QRectF(0, 1, 1, -1));
+ setPaintNode(&m_node);
connect(&m_node, SIGNAL(textureCreated(uint, const QSize &, int)), this, SLOT(textureCreated(uint, const QSize &, int)));
connect(&m_node, SIGNAL(aboutToRender()), this, SLOT(effectNodeAboutToRender()));
}
+void ShaderEffectItem::componentComplete()
+{
+ updateProperties();
+ QxItem::componentComplete();
+}
+
AbstractEffectType *ShaderEffectItem::type() const
{
return const_cast<AbstractEffectType *>(&m_type);
@@ -198,8 +220,11 @@ void ShaderEffectItem::setFragmentShader(const QString &code)
{
if (m_fragment_code.constData() == code.constData())
return;
- markShaderProgramAsDirty();
m_fragment_code = code;
+ if (isComponentComplete()) {
+ markShaderProgramAsDirty();
+ updateProperties();
+ }
emit fragmentShaderChanged();
}
@@ -207,101 +232,12 @@ void ShaderEffectItem::setVertexShader(const QString &code)
{
if (m_vertex_code.constData() == code.constData())
return;
- markShaderProgramAsDirty();
m_vertex_code = code;
- emit vertexShaderChanged();
-}
-
-void ShaderEffectItem::setSource(QxItem *item)
-{
- if (m_source == item)
- return;
-
- if (m_active && m_source) {
- QxItemPrivate *src = QxItemPrivate::get(m_source);
- m_node.setSubtree(0, EffectSubtreeNode::Source);
- src->derefFromEffectItem();
- if (!m_mask)
- setPaintNode(0);
- }
-
- if (item) {
- m_effectDepth[EffectSubtreeNode::Source] = 0;
-
- // There are two supported relations between effects and sources:
- // - source's parent is effect's ancestor, but source itself is not:
- // - Effect { source: foo }; Item { id: foo }
- // - Item { Effect { source: foo } }; Item { id: foo }
- // - effect is parent of source:
- // - Effect { source: Item { } }
- // - Effect { source: foo; Item { id: foo } }
-
- if (item->parentItem() == 0)
- item->setParentItem(this);
-
- QxItem *parent = this;
- while (parent && parent != item->parentItem()) {
- parent = parent->parentItem();
- ++m_effectDepth[EffectSubtreeNode::Source];
- }
- if (!parent) {
- qWarning("ShaderEffectItem: The source needs to be a sibling or child of the effect.");
- item = 0;
- }
- }
-
- m_source = item;
-
- if (m_active && m_source) {
- setPaintNode(&m_node);
- QxItemPrivate *src = QxItemPrivate::get(m_source);
- src->refFromEffectItem();
- m_node.setSubtree(src->rootNode, EffectSubtreeNode::Source);
- }
-
- emit sourceChanged();
-}
-
-void ShaderEffectItem::setMask(QxItem *item)
-{
- if (m_mask == item)
- return;
-
- if (m_active && m_mask) {
- QxItemPrivate *src = QxItemPrivate::get(m_mask);
- m_node.setSubtree(0, EffectSubtreeNode::Mask);
- src->derefFromEffectItem();
- if (!m_source)
- setPaintNode(0);
- }
-
- if (item) {
- m_effectDepth[EffectSubtreeNode::Mask] = 0;
-
- if (item->parentItem() == 0)
- item->setParentItem(this);
-
- QxItem *parent = this;
- while (parent && parent != item->parentItem()) {
- parent = parent->parentItem();
- ++m_effectDepth[EffectSubtreeNode::Mask];
- }
- if (!parent) {
- qWarning("ShaderEffectItem: The mask needs to be a sibling or child of the effect.");
- item = 0;
- }
- }
-
- m_mask = item;
-
- if (m_active && m_mask) {
- setPaintNode(&m_node);
- QxItemPrivate *src = QxItemPrivate::get(m_mask);
- src->refFromEffectItem();
- m_node.setSubtree(src->rootNode, EffectSubtreeNode::Mask);
+ if (isComponentComplete()) {
+ markShaderProgramAsDirty();
+ updateProperties();
}
-
- emit maskChanged();
+ emit vertexShaderChanged();
}
void ShaderEffectItem::setBlending(bool enable)
@@ -318,15 +254,12 @@ void ShaderEffectItem::setActive(bool enable)
if (m_active == enable)
return;
- if (m_active && (m_source || m_mask)) {
- if (m_source) {
- QxItemPrivate *src = QxItemPrivate::get(m_source);
- m_node.setSubtree(0, EffectSubtreeNode::Source);
- src->derefFromEffectItem();
- }
- if (m_mask) {
- QxItemPrivate *src = QxItemPrivate::get(m_mask);
- m_node.setSubtree(0, EffectSubtreeNode::Mask);
+ if (m_active) {
+ for (int i = 0; i < m_sources.size(); ++i) {
+ if (!m_sources.at(i).item)
+ continue;
+ QxItemPrivate *src = QxItemPrivate::get(m_sources.at(i).item);
+ m_node.setSubtree(0, i);
src->derefFromEffectItem();
}
setPaintNode(0);
@@ -334,17 +267,14 @@ void ShaderEffectItem::setActive(bool enable)
m_active = enable;
- if (m_active && (m_source || m_mask)) {
+ if (m_active) {
setPaintNode(&m_node);
- if (m_source) {
- QxItemPrivate *src = QxItemPrivate::get(m_source);
- src->refFromEffectItem();
- m_node.setSubtree(src->rootNode, EffectSubtreeNode::Source);
- }
- if (m_mask) {
- QxItemPrivate *src = QxItemPrivate::get(m_mask);
+ for (int i = 0; i < m_sources.size(); ++i) {
+ if (!m_sources.at(i).item)
+ continue;
+ QxItemPrivate *src = QxItemPrivate::get(m_sources.at(i).item);
src->refFromEffectItem();
- m_node.setSubtree(src->rootNode, EffectSubtreeNode::Mask);
+ m_node.setSubtree(src->rootNode, i);
}
}
@@ -374,11 +304,12 @@ void ShaderEffectItem::transformChanged(const QTransform &newTransform, const QT
void ShaderEffectItem::updateTransform()
{
- for (int i = 0; i < EffectSubtreeNode::SourceCount; ++i) {
- if (m_effectDepth[i]) {
+ for (int i = 0; i < m_sources.size(); ++i) {
+ int depth = m_sources.at(i).depth;
+ if (depth) {
QTransform t;
QxItem *current = this;
- for (int j = 0; current && j < m_effectDepth[i]; ++j) {
+ for (int j = 0; current && j < depth; ++j) {
t *= current->combinedTransform();
current = current->parentItem();
}
@@ -391,14 +322,78 @@ void ShaderEffectItem::updateTransform()
void ShaderEffectItem::textureCreated(uint id, const QSize &size, int index)
{
- Q_ASSERT(uint(index) < EffectSubtreeNode::SourceCount);
- m_texture[index] = QGLTexture2DConstPtr(QGLTexture2D::fromTextureId(id, size));
+ Q_ASSERT(index >= 0 && index < m_sources.size());
+ m_sources[index].texture = QGLTexture2DConstPtr(QGLTexture2D::fromTextureId(id, size));
m_node.markDirty(Node::DirtyMaterial);
}
+void ShaderEffectItem::changeSource(int index)
+{
+ Q_ASSERT(index >= 0 && index < m_sources.size());
+ QVariant v = property(m_sources.at(index).name.constData());
+ if (v.isValid()) {
+ QxItem *item = qobject_cast<QxItem *>(qVariantValue<QObject *>(v));
+ setSource(item, index);
+ }
+}
+
+void ShaderEffectItem::setSource(QxItem *item, int index)
+{
+ Q_ASSERT(index >= 0 && index < m_sources.size());
+
+ SourceData &source = m_sources[index];
+
+ if (source.item == item)
+ return;
+
+ if (m_active && source.item) {
+ QxItemPrivate *src = QxItemPrivate::get(source.item);
+ m_node.setSubtree(0, index);
+ src->derefFromEffectItem();
+ }
+
+ if (item) {
+ source.depth = 0;
+
+ // There are two supported relations between effects and sources:
+ // - source's parent is effect's ancestor, but source itself is not:
+ // - Effect { source: foo }; Item { id: foo }
+ // - Item { Effect { source: foo } }; Item { id: foo }
+ // - effect is parent of source:
+ // - Effect { source: Item { } }
+ // - Effect { source: foo; Item { id: foo } }
+
+ if (item->parentItem() == 0)
+ item->setParentItem(this);
+
+ QxItem *parent = this;
+ while (parent && parent != item->parentItem()) {
+ parent = parent->parentItem();
+ ++source.depth;
+ }
+ if (!parent) {
+ qWarning("ShaderEffectItem: The source needs to be a sibling or child of the effect.");
+ item = 0;
+ }
+ }
+
+ source.item = item;
+
+ if (m_active && source.item) {
+ QxItemPrivate *src = QxItemPrivate::get(source.item);
+ src->refFromEffectItem();
+ m_node.setSubtree(src->rootNode, index);
+ }
+}
+
void ShaderEffectItem::disconnectPropertySignals()
{
disconnect(this, 0, &m_node, SLOT(sceneGraphChanged()));
+ for (int i = 0; i < m_sources.size(); ++i) {
+ SourceData &source = m_sources[i];
+ disconnect(this, 0, source.mapper, 0);
+ disconnect(source.mapper, 0, this, 0);
+ }
}
void ShaderEffectItem::connectPropertySignals()
@@ -417,6 +412,20 @@ void ShaderEffectItem::connectPropertySignals()
qWarning("ShaderEffectItem: '%s' does not have a matching property!", it->constData());
}
}
+ for (int i = 0; i < m_sources.size(); ++i) {
+ SourceData &source = m_sources[i];
+ int pi = metaObject()->indexOfProperty(source.name.constData());
+ if (pi >= 0) {
+ QMetaProperty mp = metaObject()->property(pi);
+ QByteArray signalName("2");
+ signalName.append(mp.notifySignal().signature());
+ connect(this, signalName, source.mapper, SLOT(map()));
+ source.mapper->setMapping(this, i);
+ connect(source.mapper, SIGNAL(mapped(int)), this, SLOT(changeSource(int)));
+ } else {
+ qWarning("ShaderEffectItem: '%s' does not have a matching source!", source.name.constData());
+ }
+ }
}
void ShaderEffectItem::markShaderProgramAsDirty()
@@ -426,19 +435,17 @@ void ShaderEffectItem::markShaderProgramAsDirty()
m_program.removeAllShaders();
m_attributeNames.clear();
m_attributes.clear();
- m_matrixName.clear();
- m_sourceName.clear();
- m_maskName.clear();
m_uniformNames.clear();
+ for (int i = 0; i < m_sources.size(); ++i)
+ delete m_sources.at(i).mapper;
+ m_sources.clear();
m_node.markDirty(Node::DirtyMaterial);
m_program_dirty = true;
}
-void ShaderEffectItem::updateShaderProgram()
+void ShaderEffectItem::updateProperties()
{
- Q_ASSERT(m_program_dirty);
-
QString vertexCode = m_vertex_code;
QString fragmentCode = m_fragment_code;
if (vertexCode.isEmpty())
@@ -448,8 +455,32 @@ void ShaderEffectItem::updateShaderProgram()
lookThroughShaderCode(vertexCode);
lookThroughShaderCode(fragmentCode);
+ m_node.setSubtreeCount(m_sources.size());
+
+ for (int i = 0; i < m_sources.size(); ++i) {
+ QVariant v = property(m_sources.at(i).name);
+ if (v.isValid()) {
+ // Property exists.
+ QxItem *item = qobject_cast<QxItem *>(qVariantValue<QObject *>(v));
+ setSource(item, i);
+ }
+ }
+
// Append an 'end of array' marker so that m_attributes.constData() can be returned in requiredFields().
m_attributes.append(QGL::VertexAttribute(-1));
+ connectPropertySignals();
+}
+
+void ShaderEffectItem::updateShaderProgram()
+{
+ Q_ASSERT(m_program_dirty);
+
+ QString vertexCode = m_vertex_code;
+ QString fragmentCode = m_fragment_code;
+ if (vertexCode.isEmpty())
+ vertexCode = QString::fromLatin1(qt_default_vertex_code);
+ if (fragmentCode.isEmpty())
+ fragmentCode = QString::fromLatin1(qt_default_fragment_code);
m_program.addShaderFromSourceCode(QGLShader::Vertex, vertexCode);
m_program.addShaderFromSourceCode(QGLShader::Fragment, fragmentCode);
@@ -466,21 +497,15 @@ void ShaderEffectItem::updateShaderProgram()
qWarning("ShaderEffectItem: Missing reference to \'qt_Vertex\'.");
if (!m_attributes.contains(QGL::TextureCoord0))
qWarning("ShaderEffectItem: Missing reference to \'qt_MultiTexCoord0\'.");
- if (m_matrixName.isEmpty())
+ if (!m_respects_matrix)
qWarning("ShaderEffectItem: Missing reference to \'qt_Matrix\'.");
- if (m_sourceName.isEmpty())
- qWarning("ShaderEffectItem: Missing reference to \'source\'.");
if (m_program.isLinked()) {
m_program.bind();
- if (!m_sourceName.isEmpty())
- m_program.setUniformValue(m_sourceName.constData(), EffectSubtreeNode::Source);
- if (!m_maskName.isEmpty())
- m_program.setUniformValue(m_maskName.constData(), EffectSubtreeNode::Mask);
+ for (int i = 0; i < m_sources.size(); ++i)
+ m_program.setUniformValue(m_sources.at(i).name.constData(), i);
}
- connectPropertySignals();
-
m_program_dirty = false;
}
@@ -488,13 +513,14 @@ void ShaderEffectItem::lookThroughShaderCode(const QString &code)
{
// Regexp for matching attributes and uniforms.
// In human readable form: attribute|uniform [lowp|mediump|highp] <type> <name>
- static QRegExp re(QLatin1String("\\b(attribute|uniform)\\b\\s*\\b(?:lowp|mediump|highp)?\\b\\s*\\b\\w+\\b\\s*\\b(\\w+)"));
+ static QRegExp re(QLatin1String("\\b(attribute|uniform)\\b\\s*\\b(?:lowp|mediump|highp)?\\b\\s*\\b(\\w+)\\b\\s*\\b(\\w+)"));
Q_ASSERT(re.isValid());
int pos = -1;
while ((pos = re.indexIn(code, pos + 1)) != -1) {
- QString name = re.cap(2); // variable name
QString decl = re.cap(1); // uniform or attribute
+ QString type = re.cap(2); // type
+ QString name = re.cap(3); // variable name
if (decl == QLatin1String("attribute")) {
if (name == QLatin1String("qt_Vertex") || name == QLatin1String("qt_VertexPosition")) {
@@ -511,15 +537,19 @@ void ShaderEffectItem::lookThroughShaderCode(const QString &code)
Q_ASSERT(decl == QLatin1String("uniform"));
if (name == QLatin1String("qt_Matrix")) {
- m_matrixName = name.toLatin1();
- } else if (name == QLatin1String("source") || name == QLatin1String("qt_Texture")) {
- m_sourceName = name.toLatin1();
- } else if (name == QLatin1String("mask")) {
- m_maskName = name.toLatin1();
+ m_respects_matrix = true;
} else if (name == QLatin1String("qt_Opacity")) {
m_respects_opacity = true;
} else {
m_uniformNames.insert(name.toLatin1());
+ if (type == QLatin1String("sampler2D")) {
+ SourceData d;
+ d.mapper = new QSignalMapper;
+ d.item = 0;
+ d.name = name.toLatin1();
+ d.depth = 0;
+ m_sources.append(d);
+ }
}
}
}
diff --git a/src/effects/shadereffectitem.h b/src/effects/shadereffectitem.h
index 98a7317..37b944c 100644
--- a/src/effects/shadereffectitem.h
+++ b/src/effects/shadereffectitem.h
@@ -47,6 +47,7 @@
#include "material.h"
#include "adaptationinterfaces.h"
+class QSignalMapper;
class CustomShaderMaterialData;
class ShaderEffectItem : public QxItem, public AbstractEffect
@@ -54,8 +55,6 @@ class ShaderEffectItem : public QxItem, public AbstractEffect
Q_OBJECT
Q_PROPERTY(QString fragmentShader READ fragmentShader WRITE setFragmentShader NOTIFY fragmentShaderChanged);
Q_PROPERTY(QString vertexShader READ vertexShader WRITE setVertexShader NOTIFY vertexShaderChanged);
- Q_PROPERTY(QxItem *source READ source WRITE setSource NOTIFY sourceChanged);
- Q_PROPERTY(QxItem *mask READ mask WRITE setMask NOTIFY maskChanged);
Q_PROPERTY(bool blending READ blending WRITE setBlending NOTIFY blendingChanged);
Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged);
Q_PROPERTY(QSize margins READ margins WRITE setMargins NOTIFY marginsChanged);
@@ -63,6 +62,7 @@ class ShaderEffectItem : public QxItem, public AbstractEffect
public:
ShaderEffectItem(QxItem *parent = 0);
+ virtual void componentComplete();
virtual AbstractEffectType *type() const;
virtual AbstractEffectProgram *createProgram() const;
@@ -73,12 +73,6 @@ public:
QString vertexShader() const { return m_vertex_code; }
void setVertexShader(const QString &code);
- QxItem *source() const { return m_source; }
- void setSource(QxItem *item);
-
- QxItem *mask() const { return m_mask; }
- void setMask(QxItem *item);
-
bool blending() const { return flags() == Blending; }
void setBlending(bool enable);
@@ -94,8 +88,6 @@ public:
signals:
void fragmentShaderChanged();
void vertexShaderChanged();
- void sourceChanged();
- void maskChanged();
void blendingChanged();
void activeChanged();
void marginsChanged();
@@ -110,43 +102,51 @@ protected:
private slots:
void textureCreated(uint id, const QSize &size, int index);
void effectNodeAboutToRender();
+ void changeSource(int index);
private:
friend class CustomShaderMaterialData;
+ void setSource(QxItem *item, int index);
void disconnectPropertySignals();
void connectPropertySignals();
void markShaderProgramAsDirty();
+ void updateProperties();
void updateShaderProgram();
void lookThroughShaderCode(const QString &code);
void buildGeometry();
void updateTransform();
EffectSubtreeNode m_node;
- QxItem *m_source;
- QxItem *m_mask;
CustomShaderMaterialData *m_data;
AbstractEffectType m_type;
- QGLTexture2DConstPtr m_texture[EffectSubtreeNode::SourceCount];
QGLShaderProgram m_program;
QString m_fragment_code;
QString m_vertex_code;
QVector<QGL::VertexAttribute> m_attributes;
QVector<QByteArray> m_attributeNames;
- QByteArray m_matrixName;
- QByteArray m_sourceName;
- QByteArray m_maskName;
QSet<QByteArray> m_uniformNames;
QSize m_mesh_resolution;
- int m_effectDepth[EffectSubtreeNode::SourceCount];
+
+ struct SourceData
+ {
+ QSignalMapper *mapper;
+ QxItem *item;
+ QByteArray name;
+ QGLTexture2DConstPtr texture;
+ int depth;
+ };
+
+ QVector<SourceData> m_sources;
uint m_linear_filtering : 1;
uint m_program_dirty : 1;
uint m_geometry_dirty : 1;
uint m_active : 1;
+ uint m_respects_matrix : 1;
uint m_respects_opacity : 1;
};
diff --git a/src/graphicsitems/qxitem.cpp b/src/graphicsitems/qxitem.cpp
index fc66ff4..7101215 100644
--- a/src/graphicsitems/qxitem.cpp
+++ b/src/graphicsitems/qxitem.cpp
@@ -751,16 +751,18 @@ QRectF QxItem::mapToScene(const QRectF &r) const
return t.map(r).boundingRect();
}
-QPointF QxItem::mapToItem(QxItem *, const QPointF &) const
+QPointF QxItem::mapToItem(QxItem *item, const QPointF &point) const
{
- qWarning("QxItem::mapToItem(): Not impl");
- return QPointF();
+ if (item)
+ return itemTransform(item).map(point);
+ return mapToScene(point);
}
-QPointF QxItem::mapFromItem(QxItem *, const QPointF &) const
+QPointF QxItem::mapFromItem(QxItem *item, const QPointF &point) const
{
- qWarning("QxItem::mapFromItem(): Not impl");
- return QPointF();
+ if (item)
+ return item->itemTransform(this).map(point);
+ return mapFromScene(point);
}
bool QxItem::isVisible() const
@@ -1036,15 +1038,17 @@ void QxItemPrivate::updateClip()
Q_Q(QxItem);
if (clipNode) {
- Q_ASSERT(clipNode);
- Q_ASSERT(clipNode->parent() == &transformNode);
- Q_ASSERT(clipNode->childCount() == 1);
- Q_ASSERT(clipNode->childAtIndex(0) == &groupNode);
-
- // Remove the clip node from the scene graph.
- transformNode.removeChildNode(clipNode);
- clipNode->removeChildNode(&groupNode);
- transformNode.prependChildNode(&groupNode);
+ if (clipNode->parent() != 0) {
+ Q_ASSERT(clipNode);
+ Q_ASSERT(clipNode->parent() == &transformNode);
+ Q_ASSERT(clipNode->childCount() == 1);
+ Q_ASSERT(clipNode->childAtIndex(0) == &groupNode);
+
+ // Remove the clip node from the scene graph.
+ transformNode.removeChildNode(clipNode);
+ clipNode->removeChildNode(&groupNode);
+ transformNode.prependChildNode(&groupNode);
+ }
} else {
clipNode = new QxClipNode(QRectF(0, 0, 0, 0));
clipNode->setFlag(Node::OwnedByParent, false);
diff --git a/src/graphicsitems/qxitem.h b/src/graphicsitems/qxitem.h
index a1ee5a1..2e95fce 100644
--- a/src/graphicsitems/qxitem.h
+++ b/src/graphicsitems/qxitem.h
@@ -65,7 +65,9 @@ class QT_SCENEGRAPH_EXPORT QxItem : public QObject, public QDeclarativeParserSta
Q_OBJECT
Q_INTERFACES(QDeclarativeParserStatus)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged)
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(QPointF pos READ pos WRITE setPos FINAL)
Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged FINAL)
Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged FINAL)
Q_PROPERTY(qreal z READ zValue WRITE setZValue NOTIFY zChanged FINAL)
@@ -122,6 +124,13 @@ public:
QPointF mapToItem(QxItem *, const QPointF &) const;
QPointF mapFromItem(QxItem *, const QPointF &) const;
+ bool isEnabled() const { return true; }
+ void setEnabled(bool e)
+ {
+ Q_UNUSED(e);
+ emit enabledChanged();
+ }
+
bool isVisible() const;
void setVisible(bool);
@@ -253,6 +262,7 @@ Q_SIGNALS:
void wantsFocusChanged(bool);
void parentChanged(QxItem *);
void smoothChanged(bool);
+ void enabledChanged();
protected slots:
void updateTransform();
diff --git a/src/graphicsitems/qxrectangle.cpp b/src/graphicsitems/qxrectangle.cpp
index ff3b174..6d240c5 100644
--- a/src/graphicsitems/qxrectangle.cpp
+++ b/src/graphicsitems/qxrectangle.cpp
@@ -41,6 +41,7 @@
#include "qxrectangle_p.h"
#include "qxrectangle_p_p.h"
+#include "qxclipnode_p.h"
#include "geometry.h"
#include "vertexcolormaterial.h"
@@ -177,10 +178,9 @@ void QxRectangle::setRadius(qreal radius)
if (d->node)
d->node->setRadius(radius);
-#ifdef ROUNDEDRECT_CLIP
if (d->clipNode)
d->clipNode->setRadius(d->radius);
-#endif
+
emit radiusChanged();
}
@@ -247,6 +247,8 @@ void QxRectangle::componentComplete()
d->updateGradient();
d->updateBorderWidth();
d->updateBorderColor();
+ if (d->clipNode)
+ d->clipNode->setRadius(d->radius);
setPaintNode(d->node); // Must call setRect() before calling setPaintNode() for clipping to be correct.
}
diff --git a/src/scenegraph/convenience/effectnode.cpp b/src/scenegraph/convenience/effectnode.cpp
index 1ff5571..262d296 100644
--- a/src/scenegraph/convenience/effectnode.cpp
+++ b/src/scenegraph/convenience/effectnode.cpp
@@ -50,17 +50,14 @@ EffectSubtreeNode::EffectSubtreeNode()
: m_margins(0, 0)
, m_dirty(false)
{
- qMemSet(m_subtree, 0, sizeof(m_subtree));
- qMemSet(m_renderer, 0, sizeof(m_renderer));
- qMemSet(m_fbo, 0, sizeof(m_fbo));
setFlag(Node::UsePreprocess, true);
}
EffectSubtreeNode::~EffectSubtreeNode()
{
- for (int i = 0; i < SourceCount; ++i) {
- delete m_renderer[i];
- delete m_fbo[i];
+ for (int i = 0; i < m_subtrees.size(); ++i) {
+ delete m_subtrees.at(i).renderer;
+ delete m_subtrees.at(i).fbo;
}
}
@@ -69,9 +66,9 @@ void EffectSubtreeNode::setSize(const QSize &size)
if (m_size == size)
return;
- for (int i = 0; i < SourceCount; ++i) {
- delete m_fbo[i];
- m_fbo[i] = 0;
+ for (int i = 0; i < m_subtrees.size(); ++i) {
+ delete m_subtrees.at(i).fbo;
+ m_subtrees[i].fbo = 0;
}
m_dirty = true;
@@ -84,9 +81,9 @@ void EffectSubtreeNode::setMargins(const QSize &margins)
if (m_margins == margins)
return;
- for (int i = 0; i < SourceCount; ++i) {
- delete m_fbo[i];
- m_fbo[i] = 0;
+ for (int i = 0; i < m_subtrees.size(); ++i) {
+ delete m_subtrees.at(i).fbo;
+ m_subtrees[i].fbo = 0;
}
m_dirty = true;
@@ -100,21 +97,38 @@ QRectF EffectSubtreeNode::sourceRect() const
return QRectF(m_margins.width() / s.width(), 1 - m_margins.height() / s.height(), m_size.width() / s.width(), -m_size.height() / s.height());
}
+void EffectSubtreeNode::setSubtreeCount(int count)
+{
+ int oldSize = m_subtrees.size();
+ for (int i = count; i < oldSize; ++i) {
+ delete m_subtrees.at(i).renderer;
+ delete m_subtrees.at(i).fbo;
+ }
+ m_subtrees.resize(count);
+ for (int i = oldSize; i < count; ++i) {
+ SourceData &subtree = m_subtrees[i];
+ subtree.renderer = 0;
+ subtree.fbo = 0;
+ subtree.node = 0;
+ }
+}
+
void EffectSubtreeNode::setSubtree(RootNode *node, int index)
{
- Q_ASSERT(uint(index) < SourceCount);
- m_subtree[index] = node;
+ Q_ASSERT(index >= 0 && index < m_subtrees.size());
+ SourceData &subtree = m_subtrees[index];
+ subtree.node = node;
- if (m_renderer[index])
- m_renderer[index]->setRootNode(m_subtree[index]);
+ if (subtree.renderer)
+ subtree.renderer->setRootNode(subtree.node);
m_dirty = true;
markDirty(DirtyMaterial);
}
void EffectSubtreeNode::setSubtreeMatrix(const QMatrix4x4 &matrix, int index)
{
- Q_ASSERT(uint(index) < SourceCount);
- m_matrix[index] = matrix;
+ Q_ASSERT(index >= 0 && index < m_subtrees.size());
+ m_subtrees[index].matrix = matrix;
markDirty(DirtyMaterial);
}
@@ -134,8 +148,8 @@ void EffectSubtreeNode::preprocess()
emit aboutToRender();
bool hasSubtree = false;
- for (int i = 0; i < SourceCount; ++i)
- hasSubtree |= m_subtree[i] != 0;
+ for (int i = 0; i < m_subtrees.size(); ++i)
+ hasSubtree |= m_subtrees.at(i).node != 0;
if (!hasSubtree) {
qWarning("EffectSubtreeNode::preprocess: aborting because there are no root nodes\n");
return;
@@ -144,30 +158,31 @@ void EffectSubtreeNode::preprocess()
QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
QSize texSize = m_size + 2 * m_margins;
- for (int i = 0; i < SourceCount; ++i) {
- if (!m_subtree[i])
+ for (int i = 0; i < m_subtrees.size(); ++i) {
+ SourceData &subtree = m_subtrees[i];
+ if (!subtree.node)
continue;
- if (!m_renderer[i]) {
- m_renderer[i] = qt_adaptation_layer()->createRenderer();
- m_renderer[i]->setRootNode(m_subtree[i]);
- connect(m_renderer[i], SIGNAL(sceneGraphChanged()), this, SLOT(sceneGraphChanged()));
- connect(m_renderer[i], SIGNAL(sceneGraphChanged()), this, SIGNAL(repaintRequired()));
+ if (!subtree.renderer) {
+ subtree.renderer = qt_adaptation_layer()->createRenderer();
+ subtree.renderer->setRootNode(subtree.node);
+ connect(subtree.renderer, SIGNAL(sceneGraphChanged()), this, SLOT(sceneGraphChanged()));
+ connect(subtree.renderer, SIGNAL(sceneGraphChanged()), this, SIGNAL(repaintRequired()));
}
- if (!m_fbo[i]) {
- m_fbo[i] = new QGLFramebufferObject(texSize, QGLFramebufferObject::CombinedDepthStencil);
- emit textureCreated(m_fbo[i]->texture(), texSize, i);
+ if (!subtree.fbo) {
+ subtree.fbo = new QGLFramebufferObject(texSize, QGLFramebufferObject::CombinedDepthStencil);
+ emit textureCreated(subtree.fbo->texture(), texSize, i);
}
- m_renderer[i]->setDeviceRect(texSize);
- m_renderer[i]->setProjectMatrixToDeviceRect();
- QMatrix4x4 m = m_renderer[i]->projectMatrix();
+ subtree.renderer->setDeviceRect(texSize);
+ subtree.renderer->setProjectMatrixToDeviceRect();
+ QMatrix4x4 m = subtree.renderer->projectMatrix();
m.translate(m_margins.width(), m_margins.height());
- m_renderer[i]->setProjectMatrix(m * m_matrix[i]);
- m_renderer[i]->setClearColor(Qt::transparent);
+ subtree.renderer->setProjectMatrix(m * subtree.matrix);
+ subtree.renderer->setClearColor(Qt::transparent);
- m_renderer[i]->renderScene(BindableFbo(ctx, m_fbo[i]));
+ subtree.renderer->renderScene(BindableFbo(ctx, subtree.fbo));
}
m_dirty = false;
diff --git a/src/scenegraph/convenience/effectnode.h b/src/scenegraph/convenience/effectnode.h
index fbfd5b6..ca35191 100644
--- a/src/scenegraph/convenience/effectnode.h
+++ b/src/scenegraph/convenience/effectnode.h
@@ -53,8 +53,6 @@ class EffectSubtreeNode : public QObject, public GeometryNode
{
Q_OBJECT
public:
- enum SourceType { Source, Mask, SourceCount };
-
EffectSubtreeNode();
~EffectSubtreeNode();
@@ -70,11 +68,14 @@ public:
virtual NodeSubType subType() const { return EffectSubTreeNodeSubType; }
- RootNode *subtree(int index) const { Q_ASSERT(uint(index) < SourceCount); return m_subtree[index]; }
+ int subtreeCount() const { return m_subtrees.size(); }
+ void setSubtreeCount(int count);
+
+ RootNode *subtree(int index) const { Q_ASSERT(index >= 0 && index < m_subtrees.size()); return m_subtrees.at(index).node; }
void setSubtree(RootNode *node, int index);
void setSubtreeMatrix(const QMatrix4x4 &matrix, int index);
- QMatrix4x4 subtreeMatrix(int index) const { Q_ASSERT(uint(index) < SourceCount); return m_matrix[index]; }
+ QMatrix4x4 subtreeMatrix(int index) const { Q_ASSERT(index >= 0 && index < m_subtrees.size()); return m_subtrees.at(index).matrix; }
protected slots:
void sceneGraphChanged();
@@ -85,10 +86,14 @@ signals:
void aboutToRender();
protected:
- QMatrix4x4 m_matrix[SourceCount];
- RootNode *m_subtree[SourceCount];
- Renderer *m_renderer[SourceCount];
- QGLFramebufferObject *m_fbo[SourceCount];
+ struct SourceData
+ {
+ QMatrix4x4 matrix;
+ RootNode *node;
+ Renderer *renderer;
+ QGLFramebufferObject *fbo;
+ };
+ QVector<SourceData> m_subtrees;
QSize m_size;
QSize m_margins;
diff --git a/src/scenegraph/coreapi/geometry.cpp b/src/scenegraph/coreapi/geometry.cpp
index 1e8f735..3f52b34 100644
--- a/src/scenegraph/coreapi/geometry.cpp
+++ b/src/scenegraph/coreapi/geometry.cpp
@@ -46,27 +46,30 @@
#include <QApplication>
Geometry::Geometry()
- : m_isVertexDataDirty(false)
- , m_isIndexDataDirty(false)
- , m_mode(QGL::Triangles)
+ : m_mode(QGL::Triangles)
, m_vertex_stride(0)
, m_index_stride(0)
{
setIndexType(GL_UNSIGNED_SHORT);
+ GeometryDataUploader::registerGeometry(this);
}
Geometry::Geometry(const QVector<QGLAttributeDescription> &description, GLenum indexType)
- : m_isVertexDataDirty(false)
- , m_isIndexDataDirty(false)
- , m_mode(QGL::Triangles)
+ : m_mode(QGL::Triangles)
{
setIndexType(indexType);
setVertexDescription(description);
+ GeometryDataUploader::registerGeometry(this);
+}
+
+Geometry::~Geometry()
+{
+ GeometryDataUploader::unregisterGeometry(this);
}
void *Geometry::vertexData()
{
- m_isVertexDataDirty = true;
+ GeometryDataUploader::markVertexDirty();
return m_vertex_data.data();
}
@@ -81,7 +84,7 @@ void Geometry::setVertexDescription(const QVector<QGLAttributeDescription> &desc
void *Geometry::indexData()
{
- m_isIndexDataDirty = true;
+ GeometryDataUploader::markIndexDirty();
return m_index_data.data();
}
@@ -96,7 +99,7 @@ void Geometry::setIndexType(GLenum indexType)
ushort *Geometry::ushortIndexData()
{
if (m_index_type == GL_UNSIGNED_SHORT) {
- m_isIndexDataDirty = true;
+ GeometryDataUploader::markIndexDirty();
return reinterpret_cast<ushort *>(indexData());
}
return 0;
@@ -105,7 +108,7 @@ ushort *Geometry::ushortIndexData()
uint *Geometry::uintIndexData()
{
if (m_index_type == GL_UNSIGNED_INT) {
- m_isIndexDataDirty = true;
+ GeometryDataUploader::markIndexDirty();
return reinterpret_cast<uint *>(indexData());
}
return 0;
@@ -138,3 +141,138 @@ QGLAttributeValue Geometry::attributeValue(QGL::VertexAttribute attribute) const
}
return QGLAttributeValue();
}
+
+
+// Copy bigger memory blocks at once
+static inline void arraycpy(QArray<uchar> &dest, const QArray<uchar> &src)
+{
+ int extendSize = src.size();
+ int size = dest.size();
+ dest.extend(extendSize);
+ memcpy(dest.data() + size, src.data(), extendSize * sizeof(uchar));
+}
+
+bool GeometryDataUploader::m_use_buffers = true;
+QSet<const Geometry *> GeometryDataUploader::m_geometries;
+QGLBuffer GeometryDataUploader::m_vertex_buffer(QGLBuffer::VertexBuffer);
+QGLBuffer GeometryDataUploader::m_index_buffer(QGLBuffer::IndexBuffer);
+QArray<uchar> GeometryDataUploader::m_vertex_data;
+QArray<uchar> GeometryDataUploader::m_index_data;
+QHash<const Geometry *, int> GeometryDataUploader::m_vertex_offsets;
+QHash<const Geometry *, int> GeometryDataUploader::m_index_offsets;
+bool GeometryDataUploader::m_vertex_bound = false;
+bool GeometryDataUploader::m_index_bound = false;
+bool GeometryDataUploader::m_vertex_dirty = false;
+bool GeometryDataUploader::m_index_dirty = false;
+
+void GeometryDataUploader::registerGeometry(const Geometry *g)
+{
+ if (!m_use_buffers)
+ return;
+
+ m_geometries.insert(g);
+}
+
+void GeometryDataUploader::unregisterGeometry(const Geometry *g)
+{
+ if (!m_use_buffers)
+ return;
+
+ m_geometries.remove(g);
+}
+
+void GeometryDataUploader::addGeometryVertex(const Geometry *g)
+{
+ if (!m_use_buffers || g->vertexCount() == 0)
+ return;
+
+ const QArray<uchar> &vertexData = g->vertexArray();
+ m_vertex_offsets.insert(g, m_vertex_data.count());
+ arraycpy(m_vertex_data, vertexData);
+}
+
+void GeometryDataUploader::addGeometryIndex(const Geometry *g)
+{
+ if (!m_use_buffers || g->indexCount() == 0)
+ return;
+
+ if (g->indexCount()) {
+ const QArray<uchar> &indexData = g->indexArray();
+ m_index_offsets.insert(g, m_index_data.count());
+ arraycpy(m_index_data, indexData);
+ }
+}
+
+void GeometryDataUploader::bind()
+{
+ if (!m_use_buffers)
+ return;
+
+ if (!m_vertex_buffer.isCreated())
+ m_vertex_buffer.create();
+ if (!m_index_buffer.isCreated())
+ m_index_buffer.create();
+
+ if (!m_vertex_bound)
+ m_vertex_bound = m_vertex_buffer.bind();
+ if (!m_index_bound)
+ m_index_bound = m_index_buffer.bind();
+}
+
+void GeometryDataUploader::release()
+{
+ if (!m_use_buffers)
+ return;
+
+ if (m_vertex_bound)
+ m_vertex_buffer.release();
+ if (m_index_bound)
+ m_index_buffer.release();
+ m_vertex_bound = false;
+ m_index_bound = false;
+}
+
+void GeometryDataUploader::upload()
+{
+ if (!m_use_buffers || (!m_vertex_dirty && !m_index_dirty))
+ return;
+
+ bind();
+
+ if (m_vertex_dirty)
+ clearVertexData();
+ if (m_index_dirty)
+ clearIndexData();
+
+ QSet<const Geometry *>::const_iterator i;
+ for (i = m_geometries.begin(); i != m_geometries.end(); ++i) {
+ if (m_vertex_dirty)
+ addGeometryVertex(*i);
+ if (m_index_dirty)
+ addGeometryIndex(*i);
+ }
+
+ if (!m_vertex_data.isEmpty() && m_vertex_dirty)
+ m_vertex_buffer.allocate(m_vertex_data.data(), m_vertex_data.size());
+ if (!m_index_data.isEmpty() && m_index_dirty)
+ m_index_buffer.allocate(m_index_data.data(), m_index_data.size());
+
+ m_vertex_dirty = false;
+ m_index_dirty = false;
+}
+
+const void *GeometryDataUploader::vertexData(const Geometry *g, int offset)
+{
+ if (m_use_buffers)
+ return reinterpret_cast<const void *>(m_vertex_offsets.value(g) + offset);
+ else
+ return reinterpret_cast<const void *>(g->vertexArray().constData() + offset);
+}
+
+const void *GeometryDataUploader::indexData(const Geometry *g)
+{
+ if (m_use_buffers)
+ return reinterpret_cast<const void *>(m_index_offsets.value(g));
+ else
+ return g->constIndexData();
+}
diff --git a/src/scenegraph/coreapi/geometry.h b/src/scenegraph/coreapi/geometry.h
index 8a9e0b3..7876dba 100644
--- a/src/scenegraph/coreapi/geometry.h
+++ b/src/scenegraph/coreapi/geometry.h
@@ -48,13 +48,16 @@
#include <qglfunctions.h>
#include <QGLBuffer>
+#include "qmlscene_global.h"
+
class QGLAttributeValue;
-class Geometry
+class QT_SCENEGRAPH_EXPORT Geometry
{
public:
Geometry(); // Creates a null geometry.
Geometry(const QVector<QGLAttributeDescription> &description, GLenum indexType = GL_UNSIGNED_SHORT);
+ ~Geometry();
void *vertexData();
const void *constVertexData() const { return m_vertex_data.constData(); }
@@ -103,15 +106,7 @@ public:
bool isNull() const { return m_vertex_description.isEmpty(); }
- bool isVertexDataDirty() const { return m_isVertexDataDirty; }
- void setVertexDataDirty(bool d) { m_isVertexDataDirty = d; }
- bool isIndexDataDirty() const { return m_isIndexDataDirty; }
- void setIndexDataDirty(bool d) { m_isIndexDataDirty = d; }
-
protected:
- bool m_isVertexDataDirty;
- bool m_isIndexDataDirty;
-
QArray<uchar> m_vertex_data;
QArray<uchar> m_index_data;
@@ -122,4 +117,45 @@ protected:
int m_index_stride;
};
+class GeometryDataUploader
+{
+public:
+ static void registerGeometry(const Geometry *);
+ static void unregisterGeometry(const Geometry *);
+
+ static void bind();
+ static void release();
+ static void upload();
+
+ static const void *vertexData(const Geometry *g, int offset = 0);
+ static const void *indexData(const Geometry *g);
+
+ static void setUseBuffers(bool b) { m_use_buffers = b; }
+ static bool useBuffers() { return m_use_buffers; }
+
+ static void markVertexDirty() { m_vertex_dirty = true; }
+ static void markIndexDirty() { m_index_dirty = true; }
+
+private:
+ static void addGeometryVertex(const Geometry *);
+ static void addGeometryIndex(const Geometry *);
+
+ static void clearVertexData() { m_vertex_offsets.clear(); m_vertex_data.clear(); }
+ static void clearIndexData() { m_index_offsets.clear(); m_index_data.clear(); }
+
+ static bool m_use_buffers;
+ static QSet<const Geometry *> m_geometries;
+ static QGLBuffer m_vertex_buffer;
+ static QGLBuffer m_index_buffer;
+ static QArray<uchar> m_vertex_data;
+ static QArray<uchar> m_index_data;
+ static QHash<const Geometry *, int> m_vertex_offsets;
+ static QHash<const Geometry *, int> m_index_offsets;
+ static bool m_vertex_bound;
+ static bool m_index_bound;
+ static bool m_vertex_dirty;
+ static bool m_index_dirty;
+};
+
+
#endif
diff --git a/src/scenegraph/coreapi/material.h b/src/scenegraph/coreapi/material.h
index 67b0f52..aff14f8 100644
--- a/src/scenegraph/coreapi/material.h
+++ b/src/scenegraph/coreapi/material.h
@@ -45,10 +45,11 @@
#include <qglnamespace.h>
#include "renderer.h"
#include <qglshaderprogram.h>
+#include "qmlscene_global.h"
class AbstractEffect;
-class AbstractEffectProgram
+class QT_SCENEGRAPH_EXPORT AbstractEffectProgram
{
public:
virtual ~AbstractEffectProgram() { }
@@ -60,7 +61,7 @@ public:
virtual const QGL::VertexAttribute *requiredFields() const = 0; // Array must end with QGL::VertexAttribute(-1).
};
-class AbstractShaderEffectProgram : public AbstractEffectProgram
+class QT_SCENEGRAPH_EXPORT AbstractShaderEffectProgram : public AbstractEffectProgram
{
public:
AbstractShaderEffectProgram();
diff --git a/src/scenegraph/coreapi/node.cpp b/src/scenegraph/coreapi/node.cpp
index 52c38ea..d9a4cca 100644
--- a/src/scenegraph/coreapi/node.cpp
+++ b/src/scenegraph/coreapi/node.cpp
@@ -466,8 +466,8 @@ QRectF TransformNode::subtreeBoundingRect() const
RootNode::~RootNode()
{
- for (int i = 0; i < m_renderers.size(); ++i)
- m_renderers[i]->setRootNode(0);
+ while (!m_renderers.isEmpty())
+ m_renderers.last()->setRootNode(0);
destroy();
}
diff --git a/src/scenegraph/coreapi/node.h b/src/scenegraph/coreapi/node.h
index d9e8336..247710e 100644
--- a/src/scenegraph/coreapi/node.h
+++ b/src/scenegraph/coreapi/node.h
@@ -42,6 +42,7 @@
#ifndef NODE_H
#define NODE_H
+#include "qmlscene_global.h"
#include "geometry.h"
#include <QtGui/QMatrix4x4>
@@ -280,7 +281,7 @@ private:
bool m_enabled;
};
-class ClipNode : public BasicGeometryNode
+class QT_SCENEGRAPH_EXPORT ClipNode : public BasicGeometryNode
{
public:
ClipNode();
@@ -320,7 +321,7 @@ private:
};
-class RootNode : public Node
+class QT_SCENEGRAPH_EXPORT RootNode : public Node
{
public:
~RootNode();
@@ -358,9 +359,9 @@ public:
};
#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug, const Node *n);
-QDebug operator<<(QDebug, const GeometryNode *n);
-QDebug operator<<(QDebug, const TransformNode *n);
+QT_SCENEGRAPH_EXPORT QDebug operator<<(QDebug, const Node *n);
+QT_SCENEGRAPH_EXPORT QDebug operator<<(QDebug, const GeometryNode *n);
+QT_SCENEGRAPH_EXPORT QDebug operator<<(QDebug, const TransformNode *n);
class NodeDumper : public NodeVisitor {
diff --git a/src/scenegraph/coreapi/qmlrenderer.cpp b/src/scenegraph/coreapi/qmlrenderer.cpp
index ceea599..eada040 100644
--- a/src/scenegraph/coreapi/qmlrenderer.cpp
+++ b/src/scenegraph/coreapi/qmlrenderer.cpp
@@ -50,6 +50,8 @@
#include <QtGui/qapplication.h>
#include <QtCore/qpair.h>
+//#define FORCE_NO_REORDER
+
static bool nodeLessThan(GeometryNode *a, GeometryNode *b)
{
// Sort by clip...
@@ -119,14 +121,14 @@ T Heap<T, prealloc>::pop()
QMLRenderer::QMLRenderer()
- : m_dirtyVertexData(false)
- , m_dirtyIndexData(false)
+ : Renderer()
{
-#if defined(QML_RUNTIME_TESTING)
QStringList args = qApp->arguments();
+#if defined(QML_RUNTIME_TESTING)
m_render_opaque_nodes = !args.contains("--no-opaque-nodes");
m_render_alpha_nodes = !args.contains("--no-alpha-nodes");
#endif
+ GeometryDataUploader::setUseBuffers(!args.contains("--no-vbo"));
}
void QMLRenderer::render()
@@ -173,14 +175,9 @@ void QMLRenderer::render()
m_opaqueNodes.clear();
m_transparentNodes.clear();
- m_clipNodes.clear();
- int currentRenderOrder = 0;
+ int currentRenderOrder = 1;
buildLists(rootNode(), &currentRenderOrder);
- if (m_geometry_uploader.useBuffers())
- uploadNodeData();
-
- ++currentRenderOrder;
m_renderOrderMatrix.setToIdentity();
m_renderOrderMatrix.scale(1, 1, qreal(1) / currentRenderOrder);
@@ -203,8 +200,6 @@ void QMLRenderer::render()
m_currentProgram->deactivate();
m_projectionMatrix.pop();
-
- m_geometry_uploader.release();
}
class Foo : public QPair<int, GeometryNode *>
@@ -227,39 +222,30 @@ void QMLRenderer::buildLists(Node *node, int *currentRenderOrder)
g = geomNode->geometry();
if (g->vertexCount()) { //Sanity check
+#ifdef FORCE_NO_REORDER
+ if (true) {
+#else
if (geomNode->material()->flags() & AbstractEffect::Blending) {
- geomNode->setRenderOrder(*currentRenderOrder);
+#endif
+ geomNode->setRenderOrder(*currentRenderOrder - 1);
m_transparentNodes.append(geomNode);
} else {
- geomNode->setRenderOrder(*currentRenderOrder + 1);
+ geomNode->setRenderOrder(*currentRenderOrder);
m_opaqueNodes.append(geomNode);
*currentRenderOrder += 2;
}
}
- } else if (node->type() == Node::ClipNodeType) {
- ClipNode *clipNode = static_cast<ClipNode *>(node);
- g = clipNode->geometry();
-
- if (g->vertexCount()) //Sanity check
- m_clipNodes.append(clipNode);
- }
-
- if (g && m_geometry_uploader.useBuffers()) {
- if (g->isVertexDataDirty() || !m_geometry_uploader.containsGeometryVertex(g)) {
- m_dirtyVertexData = true;
- g->setVertexDataDirty(false);
- }
- if (g->isIndexDataDirty() || (g->indexCount() && !m_geometry_uploader.containsGeometryIndex(g))) {
- m_dirtyIndexData = true;
- g->setIndexDataDirty(false);
- }
}
int count = node->childCount();
if (!count)
return;
+#ifdef FORCE_NO_REORDER
+ static bool reorder = false;
+#else
static bool reorder = !qApp->arguments().contains("--no-reorder");
+#endif
if (reorder && count > 1 && (node->flags() & Node::ChildrenDoNotOverloap)) {
QVarLengthArray<int, 16> beginIndices(count);
@@ -298,51 +284,6 @@ void QMLRenderer::buildLists(Node *node, int *currentRenderOrder)
}
}
-void QMLRenderer::uploadNodeData()
-{
- m_geometry_uploader.bind();
-
- if (!m_dirtyVertexData && !m_dirtyIndexData)
- return;
-
- if (m_dirtyVertexData)
- m_geometry_uploader.clearVertexData();
- if (m_dirtyIndexData)
- m_geometry_uploader.clearIndexData();
-
- int count = m_opaqueNodes.count();
- for (int i = 0; i < count; ++i) {
- GeometryNode *geomNode = m_opaqueNodes.at(i);
- if (m_dirtyVertexData)
- m_geometry_uploader.addGeometryVertex(geomNode->geometry());
- if (m_dirtyIndexData)
- m_geometry_uploader.addGeometryIndex(geomNode->geometry());
- }
-
- count = m_transparentNodes.count();
- for (int i = 0; i < count; ++i) {
- GeometryNode *geomNode = m_transparentNodes.at(i);
- if (m_dirtyVertexData)
- m_geometry_uploader.addGeometryVertex(geomNode->geometry());
- if (m_dirtyIndexData)
- m_geometry_uploader.addGeometryIndex(geomNode->geometry());
- }
-
- count = m_clipNodes.count();
- for (int i = 0; i < count; ++i) {
- ClipNode *clipNode = m_clipNodes.at(i);
- if (m_dirtyVertexData)
- m_geometry_uploader.addGeometryVertex(clipNode->geometry());
- if (m_dirtyIndexData)
- m_geometry_uploader.addGeometryIndex(clipNode->geometry());
- }
-
- m_geometry_uploader.upload();
-
- m_dirtyVertexData = false;
- m_dirtyIndexData = false;
-}
-
void QMLRenderer::renderNodes(const QVector<GeometryNode *> &list, int renderOrders)
{
const float scale = 1.0f / renderOrders;
@@ -375,7 +316,11 @@ void QMLRenderer::renderNodes(const QVector<GeometryNode *> &list, int renderOrd
if (changeClip) {
clipType = updateStencilClip(geomNode->clipList());
m_currentClip = geomNode->clipList();
+#ifdef FORCE_NO_REORDER
+ glDepthMask(false);
+#else
glDepthMask((material->flags() & AbstractEffect::Blending) == 0);
+#endif
//++clipChangeCount;
}
@@ -422,7 +367,7 @@ void QMLRenderer::renderNodes(const QVector<GeometryNode *> &list, int renderOrd
GLboolean normalize = attr.type() != GL_FLOAT && attr.type() != GL_DOUBLE;
#endif
glVertexAttribPointer(*attributes, attr.tupleSize(), attr.type(), normalize, attr.stride(),
- m_geometry_uploader.vertexData(g, offset));
+ GeometryDataUploader::vertexData(g, offset));
offset += attr.tupleSize() * attr.sizeOfType();
} else {
qWarning("Attribute required by effect is missing.");
@@ -432,7 +377,7 @@ void QMLRenderer::renderNodes(const QVector<GeometryNode *> &list, int renderOrd
QPair<int, int> indexRange = geomNode->indexRange();
if (g->indexCount())
glDrawElements(GLenum(g->drawingMode()), indexRange.second - indexRange.first, g->indexType(),
- m_geometry_uploader.indexData(g));
+ GeometryDataUploader::indexData(g));
else
glDrawArrays(GLenum(g->drawingMode()), indexRange.first, indexRange.second - indexRange.first);
}
diff --git a/src/scenegraph/coreapi/qmlrenderer.h b/src/scenegraph/coreapi/qmlrenderer.h
index c0b7947..d2dd6f3 100644
--- a/src/scenegraph/coreapi/qmlrenderer.h
+++ b/src/scenegraph/coreapi/qmlrenderer.h
@@ -46,16 +46,14 @@
class QMLRenderer : public Renderer
{
+ Q_OBJECT
public:
QMLRenderer();
void render();
- bool allowRenderOrderUpdates() const { return false; }
-
private:
void buildLists(Node *node, int *currentRenderOrder);
- void uploadNodeData();
void renderNodes(const QVector <GeometryNode *> &list, int renderOrders);
const ClipNode *m_currentClip;
@@ -65,12 +63,8 @@ private:
QMatrix4x4 m_renderOrderMatrix;
QVector<GeometryNode *> m_opaqueNodes;
QVector<GeometryNode *> m_transparentNodes;
- QVector<ClipNode *> m_clipNodes;
QVector<GeometryNode *> m_tempNodes;
- bool m_dirtyVertexData;
- bool m_dirtyIndexData;
-
#ifdef QML_RUNTIME_TESTING
bool m_render_opaque_nodes;
bool m_render_alpha_nodes;
diff --git a/src/scenegraph/coreapi/renderer.cpp b/src/scenegraph/coreapi/renderer.cpp
index 53310ea..e082acb 100644
--- a/src/scenegraph/coreapi/renderer.cpp
+++ b/src/scenegraph/coreapi/renderer.cpp
@@ -62,125 +62,10 @@ void BindableFbo::bind() const
m_fbo->bind();
}
-// Copy bigger memory blocks at once
-static inline void arraycpy(QArray<uchar> &dest, const QArray<uchar> &src)
-{
- int extendSize = src.size();
- int size = dest.size();
- dest.extend(extendSize);
- memcpy(dest.data() + size, src.data(), extendSize * sizeof(uchar));
-}
-
-
-GeometryDataUploader::GeometryDataUploader()
- : m_use_buffers(!qApp->arguments().contains("--no-vbo"))
- , m_vertex_buffer(QGLBuffer::VertexBuffer)
- , m_index_buffer(QGLBuffer::IndexBuffer)
- , m_vertex_bound(false)
- , m_index_bound(false)
-{
-}
-
-void GeometryDataUploader::addGeometryVertex(const Geometry *g)
-{
- if (!m_use_buffers)
- return;
-
- const QArray<uchar> &vertexData = g->vertexArray();
- m_vertex_offsets.insert(g, m_vertex_data.count());
- arraycpy(m_vertex_data, vertexData);
-}
-
-void GeometryDataUploader::addGeometryIndex(const Geometry *g)
-{
- if (!m_use_buffers)
- return;
-
- if (g->indexCount()) {
- const QArray<uchar> &indexData = g->indexArray();
- m_index_offsets.insert(g, m_index_data.count());
- arraycpy(m_index_data, indexData);
- }
-}
-
-bool GeometryDataUploader::containsGeometryVertex(const Geometry *g)
-{
- if (!m_use_buffers)
- return true;
-
- return m_vertex_offsets.contains(g);
-}
-
-bool GeometryDataUploader::containsGeometryIndex(const Geometry *g)
-{
- if (!m_use_buffers)
- return true;
-
- return m_index_offsets.contains(g);
-}
-
-void GeometryDataUploader::bind()
-{
- if (!m_use_buffers)
- return;
-
- if (!m_vertex_buffer.isCreated())
- m_vertex_buffer.create();
- if (!m_index_buffer.isCreated())
- m_index_buffer.create();
-
- if (!m_vertex_bound)
- m_vertex_bound = m_vertex_buffer.bind();
- if (!m_index_bound)
- m_index_bound = m_index_buffer.bind();
-}
-
-void GeometryDataUploader::release()
-{
- if (!m_use_buffers)
- return;
-
- if (m_vertex_bound)
- m_vertex_buffer.release();
- if (m_index_bound)
- m_index_buffer.release();
- m_vertex_bound = false;
- m_index_bound = false;
-}
-
-void GeometryDataUploader::upload()
-{
- if (!m_use_buffers)
- return;
-
- bind();
-
- if (!m_vertex_data.isEmpty())
- m_vertex_buffer.allocate(m_vertex_data.data(), m_vertex_data.size());
-
- if (!m_index_data.isEmpty())
- m_index_buffer.allocate(m_index_data.data(), m_index_data.size());
-}
-
-const void *GeometryDataUploader::vertexData(const Geometry *g, int offset)
-{
- if (m_use_buffers)
- return reinterpret_cast<const void *>(m_vertex_offsets.value(g) + offset);
- else
- return reinterpret_cast<const void *>(g->vertexArray().constData() + offset);
-}
-
-const void *GeometryDataUploader::indexData(const Geometry *g)
-{
- if (m_use_buffers)
- return reinterpret_cast<const void *>(m_index_offsets.value(g));
- else
- return g->constIndexData();
-}
-
Renderer::Renderer()
- : m_clear_color(Qt::transparent)
+ : QObject()
+ , m_clear_color(Qt::transparent)
, m_root_node(0)
, m_changed_emitted(false)
{
@@ -229,7 +114,10 @@ void Renderer::renderScene(const Bindable &bindable)
preprocess();
bindable.bind();
+ GeometryDataUploader::bind();
+ GeometryDataUploader::upload();
render();
+ GeometryDataUploader::release();
m_changed_emitted = false;
}
@@ -240,7 +128,7 @@ void Renderer::setProjectMatrixToDeviceRect()
m_device_rect.x() + m_device_rect.width(),
m_device_rect.y() + m_device_rect.height(),
m_device_rect.y(),
- 100,
+ qreal(0.01),
-1);
setProjectMatrix(matrix);
}
@@ -445,14 +333,14 @@ Renderer::ClipType Renderer::updateStencilClip(const ClipNode *clip)
const QGLAttributeValue &v = geometry->attributeValue(QGL::Position);
glVertexAttribPointer(QGL::Position, v.tupleSize(), v.type(), GL_FALSE, v.stride(),
- m_geometry_uploader.vertexData(geometry));
+ GeometryDataUploader::vertexData(geometry));
m_clip_program.setUniformValue(m_clip_matrix_id, m);
QPair<int, int> range = clip->indexRange();
if (geometry->indexCount()) {
glDrawElements(GLenum(geometry->drawingMode()), range.second - range.first, geometry->indexType()
- , m_geometry_uploader.indexData(geometry));
+ , GeometryDataUploader::indexData(geometry));
} else {
glDrawArrays(GLenum(geometry->drawingMode()), range.first, range.second - range.first);
}
diff --git a/src/scenegraph/coreapi/renderer.h b/src/scenegraph/coreapi/renderer.h
index d408a5a..1d9856f 100644
--- a/src/scenegraph/coreapi/renderer.h
+++ b/src/scenegraph/coreapi/renderer.h
@@ -76,43 +76,8 @@ private:
QGLFramebufferObject *m_fbo;
};
-class GeometryDataUploader
-{
-public:
- GeometryDataUploader();
-
- void addGeometryVertex(const Geometry *);
- void addGeometryIndex(const Geometry *);
-
- bool containsGeometryVertex(const Geometry *);
- bool containsGeometryIndex(const Geometry *);
-
- void bind();
- void release();
- void upload();
-
- const void *vertexData(const Geometry *g, int offset = 0);
- const void *indexData(const Geometry *g);
-
- void clearVertexData() { m_vertex_offsets.clear(); m_vertex_data.clear(); }
- void clearIndexData() { m_index_offsets.clear(); m_index_data.clear(); }
- bool useBuffers() const { return m_use_buffers; }
-
-private:
- bool m_use_buffers;
-
- QGLBuffer m_vertex_buffer;
- QGLBuffer m_index_buffer;
- QArray<uchar> m_vertex_data;
- QArray<uchar> m_index_data;
- QHash<const Geometry *, int> m_vertex_offsets;
- QHash<const Geometry *, int> m_index_offsets;
- bool m_vertex_bound;
- bool m_index_bound;
-};
-
-class Renderer : public QObject, protected QGLFunctions
+class QT_SCENEGRAPH_EXPORT Renderer : public QObject, protected QGLFunctions
{
Q_OBJECT
public:
@@ -164,8 +129,6 @@ public:
virtual void nodeChanged(Node *node, Node::DirtyFlags flags);
virtual void materialChanged(GeometryNode *node, AbstractEffect *from, AbstractEffect *to);
- virtual bool allowRenderOrderUpdates() const = 0;
-
public slots:
signals:
@@ -186,8 +149,6 @@ protected:
QMatrix4x4Stack m_projectionMatrix;
QMatrix4x4Stack m_modelViewMatrix;
- GeometryDataUploader m_geometry_uploader;
-
private:
RootNode *m_root_node;
QRect m_device_rect;
diff --git a/src/scenegraph_include.pri b/src/scenegraph_include.pri
index b7f0b54..6b0d38e 100644
--- a/src/scenegraph_include.pri
+++ b/src/scenegraph_include.pri
@@ -10,5 +10,7 @@ INCLUDEPATH += \
$$PWD
QT += opengl declarative
-LIBS += -lQtSceneGraph -L$$PWD/../lib
+LIBS += -L$$PWD/../lib -lQtSceneGraph
DEFINES += QT_USE_SCENEGRAPH
+
+DEFINES += QML_RUNTIME_TESTING
diff --git a/tests/ColorizeEffectItem.qml b/tests/ColorizeEffectItem.qml
index 14253b3..06fea4d 100644
--- a/tests/ColorizeEffectItem.qml
+++ b/tests/ColorizeEffectItem.qml
@@ -44,6 +44,7 @@ import QtQuick 2.0
ShaderEffectItem {
property color color: "white"
property real intensity: 0.5
+ property variant source: null
fragmentShader: "varying highp vec2 qt_TexCoord; \n" +
"uniform sampler2D source; \n" +
@@ -53,4 +54,4 @@ ShaderEffectItem {
" lowp vec4 p = texture2D(source, qt_TexCoord); \n" +
" gl_FragColor = mix(p, dot(p.rgb, vec3(0.34)) * p.a * color, intensity);\n" +
"}"
-}
+}
diff --git a/tests/DirectionalBlurEffectItem.qml b/tests/DirectionalBlurEffectItem.qml
index d4ae9ad..c6596fc 100644
--- a/tests/DirectionalBlurEffectItem.qml
+++ b/tests/DirectionalBlurEffectItem.qml
@@ -93,4 +93,5 @@ ShaderEffectItem
property real spread: 1;
property real xStep: 0 / width;
property real yStep: 1 / height;
+ property variant source: null
}
diff --git a/tests/MaskEffectItem.qml b/tests/MaskEffectItem.qml
index 99ef3f4..8e703b6 100644
--- a/tests/MaskEffectItem.qml
+++ b/tests/MaskEffectItem.qml
@@ -1,6 +1,45 @@
-import QtQuick 2.0
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt scene graph research project.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
-import QtQuick 1.0
+import QtQuick 2.0
ShaderEffectItem {
fragmentShader: "varying highp vec2 qt_TexCoord; \n" +
@@ -11,4 +50,6 @@ ShaderEffectItem {
" lowp vec4 p2 = texture2D(mask, qt_TexCoord); \n" +
" gl_FragColor = p1 * p2; \n" +
"}"
-}
+ property variant source: null
+ property variant mask: null
+}
diff --git a/tests/big-flickable.qml b/tests/big-flickable.qml
new file mode 100644
index 0000000..378300b
--- /dev/null
+++ b/tests/big-flickable.qml
@@ -0,0 +1,20 @@
+import Qt 4.7
+
+Item {
+ width: 360
+ height: 640
+
+ Flickable {
+ id: flick
+ anchors.fill: parent
+
+ contentWidth: 4000
+ contentHeight: 3000
+
+ Image {
+ source: "img.png"
+ width: flick.contentWidth
+ height: flick.contentHeight
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/colorizeeffect.qml b/tests/colorizeeffect.qml
index 14e7ddd..343c7ec 100644
--- a/tests/colorizeeffect.qml
+++ b/tests/colorizeeffect.qml
@@ -53,12 +53,6 @@ Rectangle {
Item {
id: theItem
anchors.fill: parent
- Image {
- id: block
- source: "dummyimage.jpg"
- x: (parent.width - width) / 2
- y: (parent.height - height) / 2
- }
Rectangle {
x: 0;
diff --git a/tests/rrClip.qml b/tests/rrClip.qml
index 7105ba0..ece7605 100644
--- a/tests/rrClip.qml
+++ b/tests/rrClip.qml
@@ -46,14 +46,21 @@ Rectangle {
height: 480
Rectangle {
- width: 400; height: 400
+ width: 400; height: 400;
anchors.centerIn: parent
- radius: 100
+ radius: 200
+ color: "transparent"
clip: true
Rectangle {
- anchors.fill: parent
- color: "green"
+ anchors.centerIn: parent
+ width: 400; height: 400
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "white" }
+ GradientStop { position: 1.0; color: "green" }
+ }
+
+ NumberAnimation on rotation { to: 360; duration: 3000; loops: -1 }
}
}
}
diff --git a/tools/qmlscene/main.cpp b/tools/qmlscene/main.cpp
index 37f4df3..b49f194 100644
--- a/tools/qmlscene/main.cpp
+++ b/tools/qmlscene/main.cpp
@@ -229,10 +229,19 @@ protected:
struct Options
{
- Options() : originalQml(false), maximized(false), fullscreen(false), scenegraphOnGraphicsview(false), clip(false) { }
+ Options()
+ : originalQml(false)
+ , originalQmlRaster(false)
+ , maximized(false)
+ , fullscreen(false)
+ , scenegraphOnGraphicsview(false)
+ , clip(false)
+ {
+ }
QUrl file;
bool originalQml;
+ bool originalQmlRaster;
bool maximized;
bool fullscreen;
bool scenegraphOnGraphicsview;
@@ -359,8 +368,9 @@ static void usage()
qWarning(" options:");
qWarning(" --maximized................................ run maximized");
qWarning(" --fullscreen............................... run fullscreen");
- qWarning(" --original-qml............................. run using QGraphicsView instead of scenegraph");
- qWarning(" --multisample.............................. use a GL context with multisample buffer");
+ qWarning(" --original-qml............................. run using QGraphicsView instead of scenegraph (OpenGL engine)");
+ qWarning(" --original-qml-raster...................... run using QGraphicsView instead of scenegraph (Raster engine)");
+ qWarning(" --no-multisample........................... Disable multisampling (anti-aliasing)");
qWarning(" --continuous-update........................ Continuously render the scene");
qWarning(" --nonblocking-swap......................... Do not wait for v-sync to swap buffers");
qWarning(" --sg-on-gv [--clip]........................ Scenegraph on graphicsview (and clip to item)");
@@ -380,6 +390,8 @@ int main(int argc, char ** argv)
options.file = QUrl::fromLocalFile(argv[i]);
else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--original-qml"))
options.originalQml = true;
+ else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--original-qml-raster"))
+ options.originalQmlRaster = true;
else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--maximized"))
options.maximized = true;
else if (QString::fromLatin1(argv[i]).toLower() == QLatin1String("--fullscreen"))
@@ -429,7 +441,7 @@ int main(int argc, char ** argv)
loadDummyDataFiles(*engine, fi.path());
}
item->setSource(options.file);
- } else if (!options.originalQml) {
+ } else if (!options.originalQml && !options.originalQmlRaster) {
QxGraphicsView *qxView = new MyQxGraphicsView();
engine = qxView->engine();
for (int i = 0; i < imports.size(); ++i)
@@ -452,8 +464,10 @@ int main(int argc, char ** argv)
loadDummyDataFiles(*engine, fi.path());
}
gvView->setSource(options.file);
- QGLWidget *viewport = new QGLWidget(getFormat());
- gvView->setViewport(viewport);
+ if (!options.originalQmlRaster) {
+ QGLWidget *viewport = new QGLWidget(getFormat());
+ gvView->setViewport(viewport);
+ }
}
QObject::connect(engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));