~saviq/ubuntu/saucy/qtdeclarative-opensource-src/add-qtquick-delegate-range

« back to all changes in this revision

Viewing changes to src/quick/scenegraph/qsgdefaultimagenode.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 14:17:19 UTC
  • Revision ID: package-import@ubuntu.com-20130205141719-qqeyml8wslpyez52
Tags: upstream-5.0.1
ImportĀ upstreamĀ versionĀ 5.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the QtQml module of the Qt Toolkit.
 
7
**
 
8
** $QT_BEGIN_LICENSE:LGPL$
 
9
** Commercial License Usage
 
10
** Licensees holding valid commercial Qt licenses may use this file in
 
11
** accordance with the commercial license agreement provided with the
 
12
** Software or, alternatively, in accordance with the terms contained in
 
13
** a written agreement between you and Digia.  For licensing terms and
 
14
** conditions see http://qt.digia.com/licensing.  For further information
 
15
** use the contact form at http://qt.digia.com/contact-us.
 
16
**
 
17
** GNU Lesser General Public License Usage
 
18
** Alternatively, this file may be used under the terms of the GNU Lesser
 
19
** General Public License version 2.1 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL included in the
 
21
** packaging of this file.  Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 2.1 requirements
 
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
24
**
 
25
** In addition, as a special exception, Digia gives you certain additional
 
26
** rights.  These rights are described in the Digia Qt LGPL Exception
 
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
28
**
 
29
** GNU General Public License Usage
 
30
** Alternatively, this file may be used under the terms of the GNU
 
31
** General Public License version 3.0 as published by the Free Software
 
32
** Foundation and appearing in the file LICENSE.GPL included in the
 
33
** packaging of this file.  Please review the following information to
 
34
** ensure the GNU General Public License version 3.0 requirements will be
 
35
** met: http://www.gnu.org/copyleft/gpl.html.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "qsgdefaultimagenode_p.h"
 
43
 
 
44
#include <QtCore/qvarlengtharray.h>
 
45
#include <QtCore/qmath.h>
 
46
#include <QtGui/qopenglfunctions.h>
 
47
 
 
48
#include <qsgtexturematerial.h>
 
49
#include <private/qsgtexturematerial_p.h>
 
50
#include <qsgmaterial.h>
 
51
 
 
52
QT_BEGIN_NAMESPACE
 
53
 
 
54
namespace
 
55
{
 
56
    struct SmoothVertex
 
57
    {
 
58
        float x, y, u, v;
 
59
        float dx, dy, du, dv;
 
60
    };
 
61
 
 
62
    const QSGGeometry::AttributeSet &smoothAttributeSet()
 
63
    {
 
64
        static QSGGeometry::Attribute data[] = {
 
65
            QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
 
66
            QSGGeometry::Attribute::create(1, 2, GL_FLOAT, false),
 
67
            QSGGeometry::Attribute::create(2, 2, GL_FLOAT, false),
 
68
            QSGGeometry::Attribute::create(3, 2, GL_FLOAT, false)
 
69
        };
 
70
        static QSGGeometry::AttributeSet attrs = { 4, sizeof(SmoothVertex), data };
 
71
        return attrs;
 
72
    }
 
73
}
 
74
 
 
75
class SmoothTextureMaterialShader : public QSGTextureMaterialShader
 
76
{
 
77
public:
 
78
    virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
 
79
    virtual char const *const *attributeNames() const;
 
80
 
 
81
protected:
 
82
    virtual void initialize();
 
83
    virtual const char *vertexShader() const;
 
84
    virtual const char *fragmentShader() const;
 
85
 
 
86
    int m_pixelSizeLoc;
 
87
};
 
88
 
 
89
 
 
90
SmoothTextureMaterial::SmoothTextureMaterial()
 
91
{
 
92
    setFlag(RequiresFullMatrixExceptTranslate, true);
 
93
    setFlag(Blending, true);
 
94
}
 
95
 
 
96
void SmoothTextureMaterial::setTexture(QSGTexture *texture)
 
97
{
 
98
    m_texture = texture;
 
99
}
 
100
 
 
101
QSGMaterialType *SmoothTextureMaterial::type() const
 
102
{
 
103
    static QSGMaterialType type;
 
104
    return &type;
 
105
}
 
106
 
 
107
QSGMaterialShader *SmoothTextureMaterial::createShader() const
 
108
{
 
109
    return new SmoothTextureMaterialShader;
 
110
}
 
111
 
 
112
void SmoothTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
 
113
{
 
114
    if (oldEffect == 0) {
 
115
        // The viewport is constant, so set the pixel size uniform only once.
 
116
        QRect r = state.viewportRect();
 
117
        program()->setUniformValue(m_pixelSizeLoc, 2.0f / r.width(), 2.0f / r.height());
 
118
    }
 
119
    QSGTextureMaterialShader::updateState(state, newEffect, oldEffect);
 
120
}
 
121
 
 
122
char const *const *SmoothTextureMaterialShader::attributeNames() const
 
123
{
 
124
    static char const *const attributes[] = {
 
125
        "vertex",
 
126
        "multiTexCoord",
 
127
        "vertexOffset",
 
128
        "texCoordOffset",
 
129
        0
 
130
    };
 
131
    return attributes;
 
132
}
 
133
 
 
134
void SmoothTextureMaterialShader::initialize()
 
135
{
 
136
    m_pixelSizeLoc = program()->uniformLocation("pixelSize");
 
137
    QSGTextureMaterialShader::initialize();
 
138
}
 
139
 
 
140
const char *SmoothTextureMaterialShader::vertexShader() const
 
141
{
 
142
    return
 
143
            "uniform highp vec2 pixelSize; \n"
 
144
            "uniform highp mat4 qt_Matrix; \n"
 
145
            "uniform lowp float opacity; \n"
 
146
            "attribute highp vec4 vertex; \n"
 
147
            "attribute highp vec2 multiTexCoord; \n"
 
148
            "attribute highp vec2 vertexOffset; \n"
 
149
            "attribute highp vec2 texCoordOffset; \n"
 
150
            "varying highp vec2 texCoord; \n"
 
151
            "varying lowp float vertexOpacity; \n"
 
152
            "void main() { \n"
 
153
            "    highp vec4 pos = qt_Matrix * vertex; \n"
 
154
            "    gl_Position = pos; \n"
 
155
            "    texCoord = multiTexCoord; \n"
 
156
 
 
157
            "    if (vertexOffset.x != 0.) { \n"
 
158
            "        highp vec4 delta = qt_Matrix[0] * vertexOffset.x; \n"
 
159
            "        highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w; \n"
 
160
            "        highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);  \n"
 
161
            "        dir -= ndir * delta.w * pos.w; \n"
 
162
            "        highp float numerator = dot(dir, ndir * pos.w * pos.w); \n"
 
163
            "        highp float scale = 0.0; \n"
 
164
            "        if (numerator < 0.0) \n"
 
165
            "            scale = 1.0; \n"
 
166
            "        else \n"
 
167
            "            scale = min(1.0, numerator / dot(dir, dir)); \n"
 
168
            "        gl_Position += scale * delta; \n"
 
169
            "        texCoord.x += scale * texCoordOffset.x; \n"
 
170
            "    } \n"
 
171
 
 
172
            "    if (vertexOffset.y != 0.) { \n"
 
173
            "        highp vec4 delta = qt_Matrix[1] * vertexOffset.y; \n"
 
174
            "        highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w; \n"
 
175
            "        highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);  \n"
 
176
            "        dir -= ndir * delta.w * pos.w; \n"
 
177
            "        highp float numerator = dot(dir, ndir * pos.w * pos.w); \n"
 
178
            "        highp float scale = 0.0; \n"
 
179
            "        if (numerator < 0.0) \n"
 
180
            "            scale = 1.0; \n"
 
181
            "        else \n"
 
182
            "            scale = min(1.0, numerator / dot(dir, dir)); \n"
 
183
            "        gl_Position += scale * delta; \n"
 
184
            "        texCoord.y += scale * texCoordOffset.y; \n"
 
185
            "    } \n"
 
186
 
 
187
            "    bool onEdge = any(notEqual(vertexOffset, vec2(0.))); \n"
 
188
            "    bool outerEdge = all(equal(texCoordOffset, vec2(0.))); \n"
 
189
            "    vertexOpacity = onEdge && outerEdge ? 0. : opacity; \n"
 
190
            "}";
 
191
}
 
192
 
 
193
const char *SmoothTextureMaterialShader::fragmentShader() const
 
194
{
 
195
    return
 
196
            "uniform sampler2D qt_Texture; \n"
 
197
            "varying highp vec2 texCoord; \n"
 
198
            "varying lowp float vertexOpacity; \n"
 
199
            "void main() { \n"
 
200
            "    gl_FragColor = texture2D(qt_Texture, texCoord) * vertexOpacity; \n"
 
201
            "}";
 
202
}
 
203
 
 
204
QSGDefaultImageNode::QSGDefaultImageNode()
 
205
    : m_innerSourceRect(0, 0, 1, 1)
 
206
    , m_subSourceRect(0, 0, 1, 1)
 
207
    , m_antialiasing(false)
 
208
    , m_mirror(false)
 
209
    , m_dirtyGeometry(false)
 
210
    , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
 
211
{
 
212
    setMaterial(&m_materialO);
 
213
    setOpaqueMaterial(&m_material);
 
214
    setGeometry(&m_geometry);
 
215
 
 
216
#ifdef QML_RUNTIME_TESTING
 
217
    description = QLatin1String("image");
 
218
#endif
 
219
}
 
220
 
 
221
void QSGDefaultImageNode::setTargetRect(const QRectF &rect)
 
222
{
 
223
    if (rect == m_targetRect)
 
224
        return;
 
225
    m_targetRect = rect;
 
226
    m_dirtyGeometry = true;
 
227
}
 
228
 
 
229
void QSGDefaultImageNode::setInnerTargetRect(const QRectF &rect)
 
230
{
 
231
    if (rect == m_innerTargetRect)
 
232
        return;
 
233
    m_innerTargetRect = rect;
 
234
    m_dirtyGeometry = true;
 
235
}
 
236
 
 
237
void QSGDefaultImageNode::setInnerSourceRect(const QRectF &rect)
 
238
{
 
239
    if (rect == m_innerSourceRect)
 
240
        return;
 
241
    m_innerSourceRect = rect;
 
242
    m_dirtyGeometry = true;
 
243
}
 
244
 
 
245
void QSGDefaultImageNode::setSubSourceRect(const QRectF &rect)
 
246
{
 
247
    if (rect == m_subSourceRect)
 
248
        return;
 
249
    m_subSourceRect = rect;
 
250
    m_dirtyGeometry = true;
 
251
}
 
252
 
 
253
void QSGDefaultImageNode::setFiltering(QSGTexture::Filtering filtering)
 
254
{
 
255
    if (m_material.filtering() == filtering)
 
256
        return;
 
257
 
 
258
    m_material.setFiltering(filtering);
 
259
    m_materialO.setFiltering(filtering);
 
260
    m_smoothMaterial.setFiltering(filtering);
 
261
    markDirty(DirtyMaterial);
 
262
}
 
263
 
 
264
 
 
265
void QSGDefaultImageNode::setMipmapFiltering(QSGTexture::Filtering filtering)
 
266
{
 
267
    if (m_material.mipmapFiltering() == filtering)
 
268
        return;
 
269
 
 
270
    m_material.setMipmapFiltering(filtering);
 
271
    m_materialO.setMipmapFiltering(filtering);
 
272
    m_smoothMaterial.setMipmapFiltering(filtering);
 
273
    markDirty(DirtyMaterial);
 
274
}
 
275
 
 
276
void QSGDefaultImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode)
 
277
{
 
278
    if (m_material.verticalWrapMode() == wrapMode)
 
279
        return;
 
280
 
 
281
    m_material.setVerticalWrapMode(wrapMode);
 
282
    m_materialO.setVerticalWrapMode(wrapMode);
 
283
    m_smoothMaterial.setVerticalWrapMode(wrapMode);
 
284
    markDirty(DirtyMaterial);
 
285
}
 
286
 
 
287
void QSGDefaultImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode)
 
288
{
 
289
    if (m_material.horizontalWrapMode() == wrapMode)
 
290
        return;
 
291
 
 
292
    m_material.setHorizontalWrapMode(wrapMode);
 
293
    m_materialO.setHorizontalWrapMode(wrapMode);
 
294
    m_smoothMaterial.setHorizontalWrapMode(wrapMode);
 
295
    markDirty(DirtyMaterial);
 
296
}
 
297
 
 
298
 
 
299
void QSGDefaultImageNode::setTexture(QSGTexture *texture)
 
300
{
 
301
    if (texture == m_material.texture())
 
302
        return;
 
303
 
 
304
    m_material.setTexture(texture);
 
305
    m_materialO.setTexture(texture);
 
306
    m_smoothMaterial.setTexture(texture);
 
307
    // Texture cleanup
 
308
    if (texture)
 
309
        m_material.setFlag(QSGMaterial::Blending, texture->hasAlphaChannel());
 
310
    markDirty(DirtyMaterial);
 
311
 
 
312
    // Because the texture can be a different part of the atlas, we need to update it...
 
313
    m_dirtyGeometry = true;
 
314
}
 
315
 
 
316
void QSGDefaultImageNode::setAntialiasing(bool antialiasing)
 
317
{
 
318
    if (antialiasing == m_antialiasing)
 
319
        return;
 
320
    m_antialiasing = antialiasing;
 
321
    if (m_antialiasing) {
 
322
        setMaterial(&m_smoothMaterial);
 
323
        setOpaqueMaterial(0);
 
324
        setGeometry(new QSGGeometry(smoothAttributeSet(), 0));
 
325
        setFlag(OwnsGeometry, true);
 
326
    } else {
 
327
        setMaterial(&m_materialO);
 
328
        setOpaqueMaterial(&m_material);
 
329
        setGeometry(&m_geometry);
 
330
        setFlag(OwnsGeometry, false);
 
331
    }
 
332
    m_dirtyGeometry = true;
 
333
}
 
334
 
 
335
void QSGDefaultImageNode::setMirror(bool mirror)
 
336
{
 
337
    if (mirror == m_mirror)
 
338
        return;
 
339
    m_mirror = mirror;
 
340
    m_dirtyGeometry = true;
 
341
}
 
342
 
 
343
 
 
344
void QSGDefaultImageNode::update()
 
345
{
 
346
    if (m_dirtyGeometry)
 
347
        updateGeometry();
 
348
}
 
349
 
 
350
void QSGDefaultImageNode::preprocess()
 
351
{
 
352
    bool doDirty = false;
 
353
    QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(m_material.texture());
 
354
    if (t) {
 
355
        doDirty = t->updateTexture();
 
356
        updateGeometry();
 
357
    }
 
358
    bool alpha = m_material.flags() & QSGMaterial::Blending;
 
359
    if (m_material.texture() && alpha != m_material.texture()->hasAlphaChannel()) {
 
360
        m_material.setFlag(QSGMaterial::Blending, !alpha);
 
361
        doDirty = true;
 
362
    }
 
363
 
 
364
    if (doDirty)
 
365
        markDirty(DirtyMaterial);
 
366
}
 
367
 
 
368
inline static bool isPowerOfTwo(int x)
 
369
{
 
370
    // Assumption: x >= 1
 
371
    return x == (x & -x);
 
372
}
 
373
 
 
374
namespace {
 
375
    struct X { float x, tx; };
 
376
    struct Y { float y, ty; };
 
377
}
 
378
 
 
379
static inline void appendQuad(quint16 **indices, quint16 topLeft, quint16 topRight,
 
380
                              quint16 bottomLeft, quint16 bottomRight)
 
381
{
 
382
    *(*indices)++ = topLeft;
 
383
    *(*indices)++ = bottomLeft;
 
384
    *(*indices)++ = bottomRight;
 
385
    *(*indices)++ = bottomRight;
 
386
    *(*indices)++ = topRight;
 
387
    *(*indices)++ = topLeft;
 
388
}
 
389
 
 
390
void QSGDefaultImageNode::updateGeometry()
 
391
{
 
392
    Q_ASSERT(!m_targetRect.isEmpty());
 
393
    const QSGTexture *t = m_material.texture();
 
394
    if (!t) {
 
395
        QSGGeometry *g = geometry();
 
396
        g->allocate(4);
 
397
        g->setDrawingMode(GL_TRIANGLE_STRIP);
 
398
        memset(g->vertexData(), 0, g->sizeOfVertex() * 4);
 
399
    } else {
 
400
        QRectF sourceRect = t->normalizedTextureSubRect();
 
401
 
 
402
        QRectF innerSourceRect(sourceRect.x() + m_innerSourceRect.x() * sourceRect.width(),
 
403
                               sourceRect.y() + m_innerSourceRect.y() * sourceRect.height(),
 
404
                               m_innerSourceRect.width() * sourceRect.width(),
 
405
                               m_innerSourceRect.height() * sourceRect.height());
 
406
 
 
407
        bool hasMargins = m_targetRect != m_innerTargetRect;
 
408
 
 
409
        int floorLeft = qFloor(m_subSourceRect.left());
 
410
        int ceilRight = qCeil(m_subSourceRect.right());
 
411
        int floorTop = qFloor(m_subSourceRect.top());
 
412
        int ceilBottom = qCeil(m_subSourceRect.bottom());
 
413
        int hTiles = ceilRight - floorLeft;
 
414
        int vTiles = ceilBottom - floorTop;
 
415
 
 
416
        bool hasTiles = hTiles != 1 || vTiles != 1;
 
417
        bool fullTexture = innerSourceRect == QRectF(0, 0, 1, 1);
 
418
 
 
419
#ifdef QT_OPENGL_ES_2
 
420
        QOpenGLContext *ctx = QOpenGLContext::currentContext();
 
421
        bool npotSupported = ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
 
422
        QSize size = t->textureSize();
 
423
        bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height());
 
424
        bool wrapSupported = npotSupported || !isNpot;
 
425
#else
 
426
        bool wrapSupported = true;
 
427
#endif
 
428
 
 
429
        // An image can be rendered as a single quad if:
 
430
        // - There are no margins, and either:
 
431
        //   - the image isn't repeated
 
432
        //   - the source rectangle fills the entire texture so that texture wrapping can be used,
 
433
        //     and NPOT is supported
 
434
        if (!hasMargins && (!hasTiles || (fullTexture && wrapSupported))) {
 
435
            QRectF sr;
 
436
            if (!fullTexture) {
 
437
                sr = QRectF(innerSourceRect.x() + (m_subSourceRect.left() - floorLeft) * innerSourceRect.width(),
 
438
                            innerSourceRect.y() + (m_subSourceRect.top() - floorTop) * innerSourceRect.height(),
 
439
                            m_subSourceRect.width() * innerSourceRect.width(),
 
440
                            m_subSourceRect.height() * innerSourceRect.height());
 
441
            } else {
 
442
                sr = QRectF(m_subSourceRect.left() - floorLeft, m_subSourceRect.top() - floorTop,
 
443
                            m_subSourceRect.width(), m_subSourceRect.height());
 
444
            }
 
445
            if (m_mirror) {
 
446
                qreal oldLeft = sr.left();
 
447
                sr.setLeft(sr.right());
 
448
                sr.setRight(oldLeft);
 
449
            }
 
450
 
 
451
            if (m_antialiasing) {
 
452
                QSGGeometry *g = geometry();
 
453
                Q_ASSERT(g != &m_geometry);
 
454
                g->allocate(8, 14);
 
455
                g->setDrawingMode(GL_TRIANGLE_STRIP);
 
456
                SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData());
 
457
                float delta = float(qAbs(m_targetRect.width()) < qAbs(m_targetRect.height())
 
458
                        ? m_targetRect.width() : m_targetRect.height()) * 0.5f;
 
459
                float sx = float(sr.width() / m_targetRect.width());
 
460
                float sy = float(sr.height() / m_targetRect.height());
 
461
                for (int d = -1; d <= 1; d += 2) {
 
462
                    for (int j = 0; j < 2; ++j) {
 
463
                        for (int i = 0; i < 2; ++i, ++vertices) {
 
464
                            vertices->x = m_targetRect.x() + i * m_targetRect.width();
 
465
                            vertices->y = m_targetRect.y() + j * m_targetRect.height();
 
466
                            vertices->u = sr.x() + i * sr.width();
 
467
                            vertices->v = sr.y() + j * sr.height();
 
468
                            vertices->dx = (i == 0 ? delta : -delta) * d;
 
469
                            vertices->dy = (j == 0 ? delta : -delta) * d;
 
470
                            vertices->du = (d < 0 ? 0 : vertices->dx * sx);
 
471
                            vertices->dv = (d < 0 ? 0 : vertices->dy * sy);
 
472
                        }
 
473
                    }
 
474
                }
 
475
                Q_ASSERT(vertices - g->vertexCount() == g->vertexData());
 
476
                static const quint16 indices[] = {
 
477
                    0, 4, 1, 5, 3, 7, 2, 6, 0, 4,
 
478
                    4, 6, 5, 7
 
479
                };
 
480
                Q_ASSERT(g->sizeOfIndex() * g->indexCount() == sizeof(indices));
 
481
                memcpy(g->indexDataAsUShort(), indices, sizeof(indices));
 
482
            } else {
 
483
                m_geometry.allocate(4);
 
484
                m_geometry.setDrawingMode(GL_TRIANGLE_STRIP);
 
485
                QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_targetRect, sr);
 
486
            }
 
487
        } else {
 
488
            int hCells = hTiles;
 
489
            int vCells = vTiles;
 
490
            if (m_innerTargetRect.width() == 0)
 
491
                hCells = 0;
 
492
            if (m_innerTargetRect.left() != m_targetRect.left())
 
493
                ++hCells;
 
494
            if (m_innerTargetRect.right() != m_targetRect.right())
 
495
                ++hCells;
 
496
            if (m_innerTargetRect.height() == 0)
 
497
                vCells = 0;
 
498
            if (m_innerTargetRect.top() != m_targetRect.top())
 
499
                ++vCells;
 
500
            if (m_innerTargetRect.bottom() != m_targetRect.bottom())
 
501
                ++vCells;
 
502
            QVarLengthArray<X, 32> xData(2 * hCells);
 
503
            QVarLengthArray<Y, 32> yData(2 * vCells);
 
504
            X *xs = xData.data();
 
505
            Y *ys = yData.data();
 
506
 
 
507
            if (m_innerTargetRect.left() != m_targetRect.left()) {
 
508
                xs[0].x = m_targetRect.left();
 
509
                xs[0].tx = sourceRect.left();
 
510
                xs[1].x = m_innerTargetRect.left();
 
511
                xs[1].tx = innerSourceRect.left();
 
512
                xs += 2;
 
513
            }
 
514
            if (m_innerTargetRect.width() != 0) {
 
515
                xs[0].x = m_innerTargetRect.left();
 
516
                xs[0].tx = innerSourceRect.x() + (m_subSourceRect.left() - floorLeft) * innerSourceRect.width();
 
517
                ++xs;
 
518
                float b = m_innerTargetRect.width() / m_subSourceRect.width();
 
519
                float a = m_innerTargetRect.x() - m_subSourceRect.x() * b;
 
520
                for (int i = floorLeft + 1; i <= ceilRight - 1; ++i) {
 
521
                    xs[0].x = xs[1].x = a + b * i;
 
522
                    xs[0].tx = innerSourceRect.right();
 
523
                    xs[1].tx = innerSourceRect.left();
 
524
                    xs += 2;
 
525
                }
 
526
                xs[0].x = m_innerTargetRect.right();
 
527
                xs[0].tx = innerSourceRect.x() + (m_subSourceRect.right() - ceilRight + 1) * innerSourceRect.width();
 
528
                ++xs;
 
529
            }
 
530
            if (m_innerTargetRect.right() != m_targetRect.right()) {
 
531
                xs[0].x = m_innerTargetRect.right();
 
532
                xs[0].tx = innerSourceRect.right();
 
533
                xs[1].x = m_targetRect.right();
 
534
                xs[1].tx = sourceRect.right();
 
535
                xs += 2;
 
536
            }
 
537
            Q_ASSERT(xs == xData.data() + xData.size());
 
538
            if (m_mirror) {
 
539
                float leftPlusRight = m_targetRect.left() + m_targetRect.right();
 
540
                int count = xData.size();
 
541
                xs = xData.data();
 
542
                for (int i = 0; i < count >> 1; ++i)
 
543
                    qSwap(xs[i], xs[count - 1 - i]);
 
544
                for (int i = 0; i < count; ++i)
 
545
                    xs[i].x = leftPlusRight - xs[i].x;
 
546
            }
 
547
 
 
548
            if (m_innerTargetRect.top() != m_targetRect.top()) {
 
549
                ys[0].y = m_targetRect.top();
 
550
                ys[0].ty = sourceRect.top();
 
551
                ys[1].y = m_innerTargetRect.top();
 
552
                ys[1].ty = innerSourceRect.top();
 
553
                ys += 2;
 
554
            }
 
555
            if (m_innerTargetRect.height() != 0) {
 
556
                ys[0].y = m_innerTargetRect.top();
 
557
                ys[0].ty = innerSourceRect.y() + (m_subSourceRect.top() - floorTop) * innerSourceRect.height();
 
558
                ++ys;
 
559
                float b = m_innerTargetRect.height() / m_subSourceRect.height();
 
560
                float a = m_innerTargetRect.y() - m_subSourceRect.y() * b;
 
561
                for (int i = floorTop + 1; i <= ceilBottom - 1; ++i) {
 
562
                    ys[0].y = ys[1].y = a + b * i;
 
563
                    ys[0].ty = innerSourceRect.bottom();
 
564
                    ys[1].ty = innerSourceRect.top();
 
565
                    ys += 2;
 
566
                }
 
567
                ys[0].y = m_innerTargetRect.bottom();
 
568
                ys[0].ty = innerSourceRect.y() + (m_subSourceRect.bottom() - ceilBottom + 1) * innerSourceRect.height();
 
569
                ++ys;
 
570
            }
 
571
            if (m_innerTargetRect.bottom() != m_targetRect.bottom()) {
 
572
                ys[0].y = m_innerTargetRect.bottom();
 
573
                ys[0].ty = innerSourceRect.bottom();
 
574
                ys[1].y = m_targetRect.bottom();
 
575
                ys[1].ty = sourceRect.bottom();
 
576
                ys += 2;
 
577
            }
 
578
            Q_ASSERT(ys == yData.data() + yData.size());
 
579
 
 
580
            if (m_antialiasing) {
 
581
                QSGGeometry *g = geometry();
 
582
                Q_ASSERT(g != &m_geometry);
 
583
 
 
584
                g->allocate(hCells * vCells * 4 + (hCells + vCells - 1) * 4,
 
585
                            hCells * vCells * 6 + (hCells + vCells) * 12);
 
586
                g->setDrawingMode(GL_TRIANGLES);
 
587
                SmoothVertex *vertices = reinterpret_cast<SmoothVertex *>(g->vertexData());
 
588
                memset(vertices, 0, g->vertexCount() * g->sizeOfVertex());
 
589
                quint16 *indices = g->indexDataAsUShort();
 
590
 
 
591
                // The deltas are how much the fuzziness can reach into the image.
 
592
                // Only the border vertices are moved by the vertex shader, so the fuzziness
 
593
                // can't reach further into the image than the closest interior vertices.
 
594
                float leftDx = xData.at(1).x - xData.at(0).x;
 
595
                float rightDx = xData.at(xData.size() - 1).x - xData.at(xData.size() - 2).x;
 
596
                float topDy = yData.at(1).y - yData.at(0).y;
 
597
                float bottomDy = yData.at(yData.size() - 1).y - yData.at(yData.size() - 2).y;
 
598
 
 
599
                float leftDu = xData.at(1).tx - xData.at(0).tx;
 
600
                float rightDu = xData.at(xData.size() - 1).tx - xData.at(xData.size() - 2).tx;
 
601
                float topDv = yData.at(1).ty - yData.at(0).ty;
 
602
                float bottomDv = yData.at(yData.size() - 1).ty - yData.at(yData.size() - 2).ty;
 
603
 
 
604
                if (hCells == 1) {
 
605
                    leftDx = rightDx *= 0.5f;
 
606
                    leftDu = rightDu *= 0.5f;
 
607
                }
 
608
                if (vCells == 1) {
 
609
                    topDy = bottomDy *= 0.5f;
 
610
                    topDv = bottomDv *= 0.5f;
 
611
                }
 
612
 
 
613
                // This delta is how much the fuzziness can reach out from the image.
 
614
                float delta = float(qAbs(m_targetRect.width()) < qAbs(m_targetRect.height())
 
615
                                    ? m_targetRect.width() : m_targetRect.height()) * 0.5f;
 
616
 
 
617
                quint16 index = 0;
 
618
                ys = yData.data();
 
619
                for (int j = 0; j < vCells; ++j, ys += 2) {
 
620
                    xs = xData.data();
 
621
                    bool isTop = j == 0;
 
622
                    bool isBottom = j == vCells - 1;
 
623
                    for (int i = 0; i < hCells; ++i, xs += 2) {
 
624
                        bool isLeft = i == 0;
 
625
                        bool isRight = i == hCells - 1;
 
626
 
 
627
                        SmoothVertex *v = vertices + index;
 
628
 
 
629
                        quint16 topLeft = index;
 
630
                        for (int k = (isTop || isLeft ? 2 : 1); k--; ++v, ++index) {
 
631
                            v->x = xs[0].x;
 
632
                            v->u = xs[0].tx;
 
633
                            v->y = ys[0].y;
 
634
                            v->v = ys[0].ty;
 
635
                        }
 
636
 
 
637
                        quint16 topRight = index;
 
638
                        for (int k = (isTop || isRight ? 2 : 1); k--; ++v, ++index) {
 
639
                            v->x = xs[1].x;
 
640
                            v->u = xs[1].tx;
 
641
                            v->y = ys[0].y;
 
642
                            v->v = ys[0].ty;
 
643
                        }
 
644
 
 
645
                        quint16 bottomLeft = index;
 
646
                        for (int k = (isBottom || isLeft ? 2 : 1); k--; ++v, ++index) {
 
647
                            v->x = xs[0].x;
 
648
                            v->u = xs[0].tx;
 
649
                            v->y = ys[1].y;
 
650
                            v->v = ys[1].ty;
 
651
                        }
 
652
 
 
653
                        quint16 bottomRight = index;
 
654
                        for (int k = (isBottom || isRight ? 2 : 1); k--; ++v, ++index) {
 
655
                            v->x = xs[1].x;
 
656
                            v->u = xs[1].tx;
 
657
                            v->y = ys[1].y;
 
658
                            v->v = ys[1].ty;
 
659
                        }
 
660
 
 
661
                        appendQuad(&indices, topLeft, topRight, bottomLeft, bottomRight);
 
662
 
 
663
                        if (isTop) {
 
664
                            vertices[topLeft].dy = vertices[topRight].dy = topDy;
 
665
                            vertices[topLeft].dv = vertices[topRight].dv = topDv;
 
666
                            vertices[topLeft + 1].dy = vertices[topRight + 1].dy = -delta;
 
667
                            appendQuad(&indices, topLeft + 1, topRight + 1, topLeft, topRight);
 
668
                        }
 
669
 
 
670
                        if (isBottom) {
 
671
                            vertices[bottomLeft].dy = vertices[bottomRight].dy = -bottomDy;
 
672
                            vertices[bottomLeft].dv = vertices[bottomRight].dv = -bottomDv;
 
673
                            vertices[bottomLeft + 1].dy = vertices[bottomRight + 1].dy = delta;
 
674
                            appendQuad(&indices, bottomLeft, bottomRight, bottomLeft + 1, bottomRight + 1);
 
675
                        }
 
676
 
 
677
                        if (isLeft) {
 
678
                            vertices[topLeft].dx = vertices[bottomLeft].dx = leftDx;
 
679
                            vertices[topLeft].du = vertices[bottomLeft].du = leftDu;
 
680
                            vertices[topLeft + 1].dx = vertices[bottomLeft + 1].dx = -delta;
 
681
                            appendQuad(&indices, topLeft + 1, topLeft, bottomLeft + 1, bottomLeft);
 
682
                        }
 
683
 
 
684
                        if (isRight) {
 
685
                            vertices[topRight].dx = vertices[bottomRight].dx = -rightDx;
 
686
                            vertices[topRight].du = vertices[bottomRight].du = -rightDu;
 
687
                            vertices[topRight + 1].dx = vertices[bottomRight + 1].dx = delta;
 
688
                            appendQuad(&indices, topRight, topRight + 1, bottomRight, bottomRight + 1);
 
689
                        }
 
690
                    }
 
691
                }
 
692
 
 
693
                Q_ASSERT(index == g->vertexCount());
 
694
                Q_ASSERT(indices - g->indexCount() == g->indexData());
 
695
            } else {
 
696
                m_geometry.allocate(hCells * vCells * 4, hCells * vCells * 6);
 
697
                m_geometry.setDrawingMode(GL_TRIANGLES);
 
698
                QSGGeometry::TexturedPoint2D *vertices = m_geometry.vertexDataAsTexturedPoint2D();
 
699
                ys = yData.data();
 
700
                for (int j = 0; j < vCells; ++j, ys += 2) {
 
701
                    xs = xData.data();
 
702
                    for (int i = 0; i < hCells; ++i, xs += 2) {
 
703
                        vertices[0].x = vertices[2].x = xs[0].x;
 
704
                        vertices[0].tx = vertices[2].tx = xs[0].tx;
 
705
                        vertices[1].x = vertices[3].x = xs[1].x;
 
706
                        vertices[1].tx = vertices[3].tx = xs[1].tx;
 
707
 
 
708
                        vertices[0].y = vertices[1].y = ys[0].y;
 
709
                        vertices[0].ty = vertices[1].ty = ys[0].ty;
 
710
                        vertices[2].y = vertices[3].y = ys[1].y;
 
711
                        vertices[2].ty = vertices[3].ty = ys[1].ty;
 
712
 
 
713
                        vertices += 4;
 
714
                    }
 
715
                }
 
716
 
 
717
                quint16 *indices = m_geometry.indexDataAsUShort();
 
718
                for (int i = 0; i < 4 * vCells * hCells; i += 4)
 
719
                    appendQuad(&indices, i, i + 1, i + 2, i + 3);
 
720
            }
 
721
        }
 
722
    }
 
723
    markDirty(DirtyGeometry);
 
724
    m_dirtyGeometry = false;
 
725
}
 
726
 
 
727
QT_END_NAMESPACE