Navigation Menu

Skip to content

Commit

Permalink
Fixed image tiling on scene graph.
Browse files Browse the repository at this point in the history
Repeat wrapping of non-power-of-two textures is not supported
on OpenGL ES 2 by default. This commit implements a fallback
for tiled QML Images.
  • Loading branch information
Kim Motoyoshi Kalland committed May 11, 2011
1 parent 9e037da commit e3aef83
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 8 deletions.
115 changes: 110 additions & 5 deletions src/declarative/scenegraph/qsgdefaultimagenode.cpp
Expand Up @@ -43,6 +43,10 @@

#include <private/qsgtextureprovider_p.h>

#include <QtCore/qvarlengtharray.h>
#include <QtCore/qmath.h>
#include <QtOpenGL/qglfunctions.h>

QT_BEGIN_NAMESPACE

QSGDefaultImageNode::QSGDefaultImageNode()
Expand Down Expand Up @@ -159,19 +163,120 @@ void QSGDefaultImageNode::preprocess()
markDirty(DirtyMaterial);
}

inline static bool isPowerOfTwo(int x)
{
// Assumption: x >= 1
return x == (x & -x);
}

void QSGDefaultImageNode::updateGeometry()
{
const QSGTexture *t = m_material.texture();
if (!t) {
m_geometry.allocate(4);
m_geometry.setDrawingMode(GL_TRIANGLE_STRIP);
QSGGeometry::updateTexturedRectGeometry(&m_geometry, QRectF(), QRectF());
} else {
QRectF textureRect = t->textureSubRect();
QRectF sr(textureRect.x() + m_sourceRect.x() * textureRect.width(),
textureRect.y() + m_sourceRect.y() * textureRect.height(),
m_sourceRect.width() * textureRect.width(),
m_sourceRect.height() * textureRect.height());

QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr);
bool isSubRect = textureRect != QRectF(0, 0, 1, 1);
const int ceilRight = qCeil(m_sourceRect.right());
const int floorLeft = qFloor(m_sourceRect.left());
const int ceilBottom = qCeil(m_sourceRect.bottom());
const int floorTop = qFloor(m_sourceRect.top());
const int hCells = ceilRight - floorLeft;
const int vCells = ceilBottom - floorTop;
bool isRepeating = hCells > 1 || vCells > 1;

#ifdef QT_OPENGL_ES_2
const QGLContext *ctx = QGLContext::currentContext();
bool npotSupported = ctx->functions()->hasOpenGLFeature(QGLFunctions::NPOTTextures);

QSize size = t->textureSize();
bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());

if (isRepeating && (isSubRect || (isNpot && !npotSupported))) {
#else
if (isRepeating && isSubRect) {
#endif
m_geometry.allocate(hCells * vCells * 4, hCells * vCells * 6);
m_geometry.setDrawingMode(GL_TRIANGLES);
struct X { float x, tx; };
struct Y { float y, ty; };
QVarLengthArray<X, 32> xData(2 * hCells);
QVarLengthArray<Y, 32> yData(2 * vCells);
X *xs = xData.data();
Y *ys = yData.data();

xs->x = m_targetRect.left();
xs->tx = textureRect.x() + (m_sourceRect.left() - floorLeft) * textureRect.width();
++xs;
ys->y = m_targetRect.top();
ys->ty = textureRect.y() + (m_sourceRect.top() - floorTop) * textureRect.height();
++ys;

float a, b;
b = m_targetRect.width() / m_sourceRect.width();
a = m_targetRect.x() - m_sourceRect.x() * b;
for (int i = floorLeft + 1; i <= ceilRight - 1; ++i) {
xs[0].x = xs[1].x = a + b * i;
xs[0].tx = 1;
xs[1].tx = 0;
xs += 2;
}
b = m_targetRect.height() / m_sourceRect.height();
a = m_targetRect.y() - m_sourceRect.y() * b;
for (int i = floorTop + 1; i <= ceilBottom - 1; ++i) {
ys[0].y = ys[1].y = a + b * i;
ys[0].ty = 1;
ys[1].ty = 0;
ys += 2;
}

xs->x = m_targetRect.right();
xs->tx = textureRect.x() + (m_sourceRect.right() - ceilRight + 1) * textureRect.width();

ys->y = m_targetRect.bottom();
ys->ty = textureRect.y() + (m_sourceRect.bottom() - ceilBottom + 1) * textureRect.height();

QSGGeometry::TexturedPoint2D *vertices = m_geometry.vertexDataAsTexturedPoint2D();
ys = yData.data();
for (int j = 0; j < vCells; ++j, ys += 2) {
xs = xData.data();
for (int i = 0; i < hCells; ++i, xs += 2) {
vertices[0].x = vertices[2].x = xs[0].x;
vertices[0].tx = vertices[2].tx = xs[0].tx;
vertices[1].x = vertices[3].x = xs[1].x;
vertices[1].tx = vertices[3].tx = xs[1].tx;

vertices[0].y = vertices[1].y = ys[0].y;
vertices[0].ty = vertices[1].ty = ys[0].ty;
vertices[2].y = vertices[3].y = ys[1].y;
vertices[2].ty = vertices[3].ty = ys[1].ty;

vertices += 4;
}
}

quint16 *indices = m_geometry.indexDataAsUShort();
for (int i = 0; i < 4 * vCells * hCells; i += 4) {
*indices++ = i;
*indices++ = i + 2;
*indices++ = i + 3;
*indices++ = i + 3;
*indices++ = i + 1;
*indices++ = i;
}
} else {
QRectF sr(textureRect.x() + m_sourceRect.x() * textureRect.width(),
textureRect.y() + m_sourceRect.y() * textureRect.height(),
m_sourceRect.width() * textureRect.width(),
m_sourceRect.height() * textureRect.height());

m_geometry.allocate(4);
m_geometry.setDrawingMode(GL_TRIANGLE_STRIP);
QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr);
}
}
markDirty(DirtyGeometry);
m_dirtyGeometry = false;
Expand Down
24 changes: 21 additions & 3 deletions src/declarative/scenegraph/util/qsgtexturematerial.cpp
Expand Up @@ -41,10 +41,17 @@

#include "qsgtexturematerial_p.h"

#include <qglshaderprogram.h>
#include <QtOpenGL/qglshaderprogram.h>
#include <QtOpenGL/qglfunctions.h>

QT_BEGIN_NAMESPACE

inline static bool isPowerOfTwo(int x)
{
// Assumption: x >= 1
return x == (x & -x);
}

const char qt_scenegraph_texture_material_vertex_code[] =
"uniform highp mat4 qt_Matrix; \n"
"attribute highp vec4 qt_VertexPosition; \n"
Expand Down Expand Up @@ -95,8 +102,19 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
QSGTexture *t = tx->texture();

t->setFiltering(tx->filtering());
t->setHorizontalWrapMode(tx->horizontalWrapMode());
t->setVerticalWrapMode(tx->verticalWrapMode());
#ifdef QT_OPENGL_ES_2
bool npotSupported = state.context()->functions()->hasOpenGLFeature(QGLFunctions::NPOTTextures);
QSize size = t->textureSize();
bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
if (!npotSupported && isNpot) {
t->setHorizontalWrapMode(QSGTexture::ClampToEdge);
t->setVerticalWrapMode(QSGTexture::ClampToEdge);
} else
#endif
{
t->setHorizontalWrapMode(tx->horizontalWrapMode());
t->setVerticalWrapMode(tx->verticalWrapMode());
}
t->setMipmapFiltering(tx->mipmapFiltering());

if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId())
Expand Down

0 comments on commit e3aef83

Please sign in to comment.