summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKim Motoyoshi Kalland <kim.kalland@nokia.com>2010-11-25 15:05:42 +0100
committerKim Motoyoshi Kalland <kim.kalland@nokia.com>2010-11-26 12:36:26 +0100
commitfd21d414f97bee3fdfa7cf4a9485b212626a78df (patch)
tree0fc33abf6f7bc3a63acd64d5121e55fdd7b36761
parent7edfc33d3c94a166f810c2cf8b6de77adf9c44ab (diff)
Implemented mipmapped ShaderEffectSource.
-rw-r--r--src/effects/shadereffectitem.cpp106
-rw-r--r--src/effects/shadereffectitem.h2
-rw-r--r--tests/effects.qml114
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 }
+ }
+ }
}