diff options
author | Kim Motoyoshi Kalland <kim.kalland@nokia.com> | 2010-11-25 15:05:42 +0100 |
---|---|---|
committer | Kim Motoyoshi Kalland <kim.kalland@nokia.com> | 2010-11-26 12:36:26 +0100 |
commit | fd21d414f97bee3fdfa7cf4a9485b212626a78df (patch) | |
tree | 0fc33abf6f7bc3a63acd64d5121e55fdd7b36761 | |
parent | 7edfc33d3c94a166f810c2cf8b6de77adf9c44ab (diff) |
Implemented mipmapped ShaderEffectSource.
-rw-r--r-- | src/effects/shadereffectitem.cpp | 106 | ||||
-rw-r--r-- | src/effects/shadereffectitem.h | 2 | ||||
-rw-r--r-- | tests/effects.qml | 114 |
3 files changed, 182 insertions, 40 deletions
diff --git a/src/effects/shadereffectitem.cpp b/src/effects/shadereffectitem.cpp index 28a48db..8c179d8 100644 --- a/src/effects/shadereffectitem.cpp +++ b/src/effects/shadereffectitem.cpp @@ -115,38 +115,8 @@ void CustomShaderMaterialData::updateEffectState(Renderer *r, AbstractEffect *ne if (!source.source) continue; - bool linear = source.source->filtering() == ShaderEffectSource::Linear; - ShaderEffectSource::FilterMode mipmap = source.source->mipmap(); - - GLint filtering = GL_NEAREST; - switch (mipmap) { - case ShaderEffectSource::Nearest: - filtering = linear ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST; - break; - case ShaderEffectSource::Linear: - filtering = linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR; - break; - default: - filtering = linear ? GL_LINEAR : GL_NEAREST; - break; - } - - GLuint hwrap = source.source->horizontalWrap() == ShaderEffectSource::Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE; - GLuint vwrap = source.source->verticalWrap() == ShaderEffectSource::Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE; - r->glActiveTexture(GL_TEXTURE0 + i); -#if !defined(QT_OPENGL_ES_2) - glEnable(GL_TEXTURE_2D); -#endif - if (source.source->texture().isNull()) - glBindTexture(GL_TEXTURE_2D, 0); - else - source.source->texture()->bind(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, hwrap); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vwrap); + source.source->bind(); } if (q->m_respects_opacity) @@ -282,6 +252,21 @@ void ShaderEffectSource::setMipmap(FilterMode mode) if (mode == m_mipmap) return; m_mipmap = mode; + if (m_mipmap != None) { + // Mipmap enabled, need to reallocate the textures. + if (m_fbo && !m_fbo->format().mipmap()) { + Q_ASSERT(m_sourceItem); + delete m_fbo; + m_fbo = 0; + } else if (!m_texture.isNull()) { + Q_ASSERT(!m_sourceImage.isEmpty()); + if (~m_texture->bindOptions() & QGLContext::MipmapBindOption) { + m_texture.clear(); + updateSizeAndTexture(); + } + } + m_dirtyTexture = true; + } emit mipmapChanged(); emit repaintRequired(); } @@ -342,6 +327,43 @@ void ShaderEffectSource::setStatic(bool s) emit repaintRequired(); } +void ShaderEffectSource::bind() const +{ + bool linear = m_filtering == Linear; + + GLint filtering = GL_NEAREST; + switch (m_mipmap) { + case Nearest: + filtering = linear ? GL_LINEAR_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_NEAREST; + break; + case Linear: + filtering = linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR; + break; + default: + filtering = linear ? GL_LINEAR : GL_NEAREST; + break; + } + + GLuint hwrap = m_horizontalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE; + GLuint vwrap = m_verticalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE; + +#if !defined(QT_OPENGL_ES_2) + glEnable(GL_TEXTURE_2D); +#endif + if (m_fbo) { + glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); + } else if (!m_texture.isNull()) { + m_texture->bind(); + } else { + glBindTexture(GL_TEXTURE_2D, 0); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, hwrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, vwrap); +} + void ShaderEffectSource::refFromEffectItem() { if (m_refs++ == 0) { @@ -379,10 +401,16 @@ void ShaderEffectSource::update() Q_ASSERT(src->rootNode && src->rootNode == m_renderer->rootNode()); Q_ASSERT(m_renderer); + const QGLContext *ctx = QGLContext::currentContext(); + if (m_renderer->openGLFeatures() == 0) + m_renderer->initializeGLFunctions(ctx); + if (!m_fbo) { // TODO: Implement support for multisampling. - m_fbo = new QGLFramebufferObject(m_size, QGLFramebufferObject::CombinedDepthStencil); - m_texture = QGLTexture2DPtr(QGLTexture2D::fromTextureId(m_fbo->texture(), m_fbo->size())); + QGLFramebufferObjectFormat format; + format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); + format.setMipmap(m_mipmap != None); + m_fbo = new QGLFramebufferObject(m_size, format); } Q_ASSERT(m_size == m_fbo->size()); @@ -393,10 +421,14 @@ void ShaderEffectSource::update() m_renderer->setClearColor(Qt::transparent); m_renderer->renderScene(BindableFbo(const_cast<QGLContext *>(QGLContext::currentContext()), m_fbo)); + if (m_mipmap != None) { + QGLFramebufferObject::bindDefault(); + glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); + m_renderer->glGenerateMipmap(GL_TEXTURE_2D); + } m_dirtySceneGraph = false; } m_dirtyTexture = false; - // TODO: Update mipmap. } void ShaderEffectSource::markSceneGraphDirty() @@ -427,7 +459,6 @@ void ShaderEffectSource::updateSizeAndTexture() if (m_fbo && m_fbo->size() != size) { delete m_fbo; m_fbo = 0; - m_texture.clear(); } if (m_size.width() != size.width()) { m_size.setWidth(size.width()); @@ -442,11 +473,12 @@ void ShaderEffectSource::updateSizeAndTexture() if (m_fbo) { delete m_fbo; m_fbo = 0; - m_texture.clear(); } if (!m_sourceImage.isEmpty()) { m_texture = QGLTexture2DPtr(new QGLTexture2D); - m_texture->setBindOptions(QGLContext::InternalBindOption); + QGLContext::BindOption mipmap = m_mipmap != None + ? QGLContext::MipmapBindOption : QGLContext::BindOption(0); + m_texture->setBindOptions(QGLContext::InternalBindOption | mipmap); // TODO: Implement async loading and loading over network. QImageReader reader(m_sourceImage.toLocalFile()); diff --git a/src/effects/shadereffectitem.h b/src/effects/shadereffectitem.h index 591bc0b..689ef64 100644 --- a/src/effects/shadereffectitem.h +++ b/src/effects/shadereffectitem.h @@ -122,7 +122,7 @@ public: bool isActive() const { return m_refs; } - QGLTexture2DConstPtr texture() const { return qSharedPointerConstCast<const QGLTexture2D>(m_texture); } + void bind() const; void refFromEffectItem(); void derefFromEffectItem(); diff --git a/tests/effects.qml b/tests/effects.qml index a757e39..3f7786c 100644 --- a/tests/effects.qml +++ b/tests/effects.qml @@ -4,7 +4,7 @@ Rectangle { id: topLevel width: 360 height: 540 - color: "black" + color: "#000040" Component { id: whiteBorder @@ -73,6 +73,7 @@ Rectangle { id: effectSource1 sourceItem: sourceItem1 filtering: ShaderEffectSource.Linear + mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } } @@ -148,6 +149,7 @@ Rectangle { id: effectSource2 sourceItem: sourceItem2 filtering: ShaderEffectSource.Linear + mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } Text { @@ -231,6 +233,7 @@ Rectangle { id: effectSource3 sourceItem: sourceItem3 filtering: ShaderEffectSource.Linear + mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } Text { @@ -292,6 +295,7 @@ Rectangle { id: effectSource4 sourceImage: sourceItem4.source filtering: ShaderEffectSource.Linear + mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } } @@ -365,6 +369,7 @@ Rectangle { id: effectSource5 sourceItem: sourceItem5 filtering: ShaderEffectSource.Linear + mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } Text { @@ -426,6 +431,7 @@ Rectangle { id: effectSource6 sourceImage: sourceItem6.source filtering: ShaderEffectSource.Linear + mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } } @@ -519,6 +525,7 @@ Rectangle { } } filtering: ShaderEffectSource.Linear + mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } @@ -528,6 +535,7 @@ Rectangle { y: parent.height / 2 width: parent.width / 2 height: parent.height / 4 + scale: controls.value property color color: "red" property variant source: defaultSource property real intensity @@ -569,6 +577,7 @@ Rectangle { y: parent.height / 2 width: parent.width / 2 height: parent.height / 4 + scale: controls.value property color color: "green" property alias source: innerInnerEffect2._source property real radius: 8 @@ -681,6 +690,7 @@ Rectangle { y: parent.height * 3 / 4 width: parent.width / 2 height: parent.height / 4 + scale: controls.value property color color: "blue" property variant source: defaultSource property real intensity @@ -697,7 +707,7 @@ Rectangle { " lowp vec4 pix = texture2D(source, qt_TexCoord); \n" + " highp float lo = minc(pix.xyz); \n" + " highp float hi = maxc(pix.xyz); \n" + - " gl_FragColor = qt_Opacity * mix(pix, vec4(color.xyz * (hi - lo) + lo, color.w), intensity); \n" + + " gl_FragColor = qt_Opacity * vec4(mix(pix.xyz, color.xyz * (hi - lo) + lo, intensity), pix.w); \n" + "}" SequentialAnimation on intensity { loops: Animation.Infinite @@ -719,4 +729,104 @@ Rectangle { visible: !parent.active } } + + Item { + id: controls + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + height: parent.height / 4 + property real value: 1 + property real min: 0.1 + property real max: 1 + property bool mipmap: false + Behavior on value { + animation: NumberAnimation { duration: 200 } + } + MouseArea { + anchors.left: parent.left + anchors.bottom: parent.bottom + height: parent.height / 2 + width: height + scale: parent.value <= parent.min + 0.0001 ? 0.5 : 1 + Behavior on scale { + animation: NumberAnimation { duration: 200 } + } + Rectangle { + anchors.fill: parent + anchors.margins: parent.width / 8 + color: "transparent" + border.width: 4 + border.color: "white" + radius: width / 2 + Rectangle { + color: "white" + anchors.centerIn: parent + width: parent.width / 2 + height: 4 + } + } + onClicked: { parent.value = Math.max(0.8 * parent.value, parent.min) } + } + MouseArea { + anchors.right: parent.right + anchors.bottom: parent.bottom + height: parent.height / 2 + width: height + scale: parent.value >= parent.max - 0.0001 ? 0.5 : 1 + Behavior on scale { + animation: NumberAnimation { duration: 200 } + } + Rectangle { + anchors.fill: parent + anchors.margins: parent.width / 8 + color: "transparent" + border.width: 4 + border.color: "white" + radius: width / 2 + Rectangle { + color: "white" + anchors.centerIn: parent + width: parent.width / 2 + height: 4 + } + Rectangle { + color: "white" + anchors.centerIn: parent + width: 4 + height: parent.height / 2 + } + } + onClicked: { parent.value = Math.min(1.25 * parent.value, parent.max) } + } + MouseArea { + anchors.left: parent.left + anchors.top: parent.top + height: parent.height / 2 + width: height + Rectangle { + anchors.fill: parent + anchors.margins: parent.width / 8 + color: "transparent" + border.width: 4 + border.color: "white" + radius: width / 2 + Text { + anchors.centerIn: parent + color: "white" + font.pixelSize: parent.height * 0.3 + horizontalAlignment: Text.AlignHCenter + text: "MIP\nMAP" + } + Rectangle { + anchors.centerIn: parent + width: parent.width + height: 4 + rotation: -45 + visible: !controls.mipmap + } + } + onClicked: { parent.mipmap = !parent.mipmap } + } + } } |