diff options
author | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-11-19 15:11:43 +0100 |
---|---|---|
committer | Gunnar Sletta <gunnar.sletta@nokia.com> | 2010-11-19 15:11:43 +0100 |
commit | 600e0e08c20255e674b1102aa4d2d1c6ef49091d (patch) | |
tree | d64a79cfd1ccb669041f7179d3e383255beca6c0 | |
parent | b330749f1eb915db5493a3b1bbc1420c64868307 (diff) | |
parent | 651bed285a79ba2d541d061abb641ad074607b79 (diff) |
Merge branch 'master' of scm.dev.nokia.troll.no:research/qt-scene-graph
35 files changed, 749 insertions, 603 deletions
@@ -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(), ¤tRenderOrder); - 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())); |