~loic.molinari/ubuntu-ui-toolkit/ubuntu-ui-toolkit-dynamic-shapes-for-new-design

« back to all changes in this revision

Viewing changes to src/Ubuntu/Components/plugin/privates/shape/frame.cpp

  • Committer: Loïc Molinari
  • Date: 2016-03-23 10:50:18 UTC
  • Revision ID: loic.molinari@canonical.com-20160323105018-snlrk6x8aepojb8h
Added support for distance and angle for outer shadows and fixed some bugs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
#include "frame.h"
20
20
#include <QtGui/QOpenGLFunctions>
 
21
#include <QtGui/QGuiApplication>
21
22
 
22
23
const UCFrame::Shape defaultShape = UCFrame::Squircle;
23
24
const QRgb defaultColor = qRgba(255, 255, 255, 255);
113
114
    return otherFrameCornerMaterial->innerTextureId() - m_textureId[1];
114
115
}
115
116
 
 
117
void UCFrameCornerMaterial::updateTexture(int index, UCFrame::Shape shape, int radius)
 
118
{
 
119
    DASSERT(index >= 0 && index < 2);
 
120
    DASSERT(radius >= 0);
 
121
    m_textureId[index] = m_textureFactory.shapeTexture(
 
122
        index, static_cast<Texture::Shape>(shape), radius);
 
123
}
 
124
 
116
125
// --- Node ---
117
126
 
118
127
UCFrameCornerNode::UCFrameCornerNode(UCFrame::Shape shape, bool visible)
126
135
    , m_visible(visible)
127
136
{
128
137
    setFlag(QSGNode::UsePreprocess);
129
 
    memcpy(m_geometry.indexData(), indices(), 26 * sizeof(unsigned short));
 
138
    memcpy(m_geometry.indexData(), indices(), 26 * sizeof(quint16));
130
139
    m_geometry.setDrawingMode(GL_TRIANGLE_STRIP);
131
140
    m_geometry.setIndexDataPattern(QSGGeometry::StaticPattern);
132
141
    m_geometry.setVertexDataPattern(QSGGeometry::AlwaysUploadPattern);
136
145
}
137
146
 
138
147
// static
139
 
const unsigned short* UCFrameCornerNode::indices()
 
148
const quint16* UCFrameCornerNode::indices()
140
149
{
141
150
    // The geometry is made of 20 vertices indexed with a triangle strip mode.
142
151
    //     0 -1       2- 3
148
157
    //    12  \       /  13
149
158
    //     |   14   15   |
150
159
    //    16 -17     18- 19
151
 
    static const unsigned short indices[] = {
 
160
    static const quint16 indices[] = {
152
161
        0, 6, 1, 8, 4,
153
162
        4, 5,  // Degenerate triangle.
154
163
        5, 9, 2, 7, 3,
202
211
{
203
212
    UCFrameCornerNode::Vertex* v =
204
213
        reinterpret_cast<UCFrameCornerNode::Vertex*>(m_geometry.vertexData());
 
214
    const float devicePixelRatio = qGuiApp->devicePixelRatio();
205
215
    const float w = static_cast<float>(itemSize.width());
206
216
    const float h = static_cast<float>(itemSize.height());
207
217
    // FIXME(loicm) Rounded down since renderShape() doesn't support sub-pixel rendering.
208
218
    const float maxSize = floorf(qMin(w, h) * 0.5f);
209
219
    const float clampedThickness = qMin(thickness, maxSize);
 
220
    const float deviceThickness = clampedThickness * devicePixelRatio;
210
221
    const float border = 1.0f;
211
222
    const float outerRadius = qMin(radius, maxSize);
 
223
    const float deviceOuterRadius = outerRadius * devicePixelRatio;
212
224
    // FIXME(loicm) Rounded down since renderShape() doesn't support sub-pixel rendering.
213
 
    const float innerRadius = floorf(outerRadius * ((maxSize - clampedThickness) / maxSize));
214
225
    const float outerRadiusRounded =
215
 
        getStride(static_cast<int>(outerRadius + 2 * border), 1, textureStride);
 
226
        getStride(static_cast<int>(deviceOuterRadius + 2 * border), 1, textureStride);
 
227
    const float innerRadius = floorf(outerRadius * ((maxSize - clampedThickness) / maxSize));
 
228
    const float deviceInnerRadius = innerRadius * devicePixelRatio;
216
229
    const float innerRadiusRounded =
217
 
        getStride(static_cast<int>(innerRadius + 2 * border), 1, textureStride);
 
230
        getStride(static_cast<int>(deviceInnerRadius + 2 * border), 1, textureStride);
218
231
 
219
 
    const float outerRadiusOffset = outerRadiusRounded - outerRadius - border;
 
232
    const float outerRadiusOffset = outerRadiusRounded - deviceOuterRadius - border;
220
233
    const float outerTextureFactor = 1.0f / outerRadiusRounded;
221
234
    const float outerS0 = outerTextureFactor * outerRadiusOffset;
222
 
    const float outerS1 = outerTextureFactor * (outerRadiusOffset + outerRadius);
223
 
    const float outerS2 = outerTextureFactor * (outerRadiusOffset + clampedThickness);
224
 
    const float outerS3 = outerTextureFactor * (outerRadiusOffset + clampedThickness + innerRadius);
 
235
    const float outerS1 = outerTextureFactor * (outerRadiusOffset + deviceOuterRadius);
 
236
    const float outerS2 = outerTextureFactor * (outerRadiusOffset + deviceThickness);
 
237
    const float outerS3 =
 
238
        outerTextureFactor * (outerRadiusOffset + deviceThickness + deviceInnerRadius);
225
239
 
226
 
    const float innerRadiusOffset = innerRadiusRounded - innerRadius - border;
 
240
    const float innerRadiusOffset = innerRadiusRounded - deviceInnerRadius - border;
227
241
    const float innerTextureFactor = 1.0f / innerRadiusRounded;
228
242
    const float innerS0 = innerTextureFactor * innerRadiusOffset;
229
 
    const float innerS1 = innerTextureFactor * (innerRadiusOffset + innerRadius);
230
 
    const float innerS2 = innerTextureFactor * (innerRadiusOffset - clampedThickness);
231
 
    const float innerS3 = innerTextureFactor * (innerRadiusOffset - clampedThickness + outerRadius);
 
243
    const float innerS1 = innerTextureFactor * (innerRadiusOffset + deviceInnerRadius);
 
244
    const float innerS2 = innerTextureFactor * (innerRadiusOffset - deviceThickness);
 
245
    const float innerS3 =
 
246
        innerTextureFactor * (innerRadiusOffset - deviceThickness + deviceOuterRadius);
232
247
 
233
248
    const quint32 packedColor = packColor(color);
234
249
 
383
398
    markDirty(QSGNode::DirtyGeometry);
384
399
 
385
400
    // Update data for the preprocess() call.
386
 
    if (m_radius[0] != static_cast<quint8>(outerRadius)) {
387
 
        m_newRadius[0] = static_cast<quint8>(outerRadius);
 
401
    if (m_radius[0] != static_cast<quint8>(deviceOuterRadius)) {
 
402
        m_newRadius[0] = static_cast<quint8>(deviceOuterRadius);
388
403
    }
389
 
    if (m_radius[1] != static_cast<quint8>(innerRadius)) {
390
 
        m_newRadius[1] = static_cast<quint8>(innerRadius);
 
404
    if (m_radius[1] != static_cast<quint8>(deviceInnerRadius)) {
 
405
        m_newRadius[1] = static_cast<quint8>(deviceInnerRadius);
391
406
    }
392
407
}
393
408
 
394
 
UCFrameNode::UCFrameNode()
 
409
UCFrameNode::UCFrameNode(bool blending)
395
410
    : QSGGeometryNode()
 
411
    , m_opaqueMaterial(blending)
396
412
    , m_geometry(attributeSet(), 16, 22, GL_UNSIGNED_SHORT)
397
413
{
398
414
    memcpy(m_geometry.indexData(), indices(), 22 * sizeof(quint16));
406
422
}
407
423
 
408
424
// static
409
 
const unsigned short* UCFrameNode::indices()
 
425
const quint16* UCFrameNode::indices()
410
426
{
411
427
    // The geometry is made of 16 vertices indexed with a triangle strip mode.
412
428
    //        0 ----- 1
418
434
    //    10             11
419
435
    //        12 --- 13
420
436
    //       14 ----- 15
421
 
    static const unsigned short indices[] = {
 
437
    static const quint16 indices[] = {
422
438
        0, 2, 1, 3,
423
439
        3, 4,  // Degenerate triangle.
424
440
        4, 10, 6, 8,
443
459
    return attributeSet;
444
460
}
445
461
 
 
462
void UCFrameNode::updateBlending(bool blending)
 
463
{
 
464
    m_opaqueMaterial.setFlag(QSGMaterial::Blending, blending);
 
465
    markDirty(QSGNode::DirtyMaterial);
 
466
}
 
467
 
446
468
void UCFrameNode::updateGeometry(const QSizeF& itemSize, float thickness, float radius, QRgb color)
447
469
{
448
470
    UCFrameNode::Vertex* v =
560
582
{
561
583
    const QRgb rgbColor = qRgba(color.red(), color.green(), color.blue(), color.alpha());
562
584
    if (m_color != rgbColor) {
 
585
        if ((qAlpha(m_color) < 255) != (qAlpha(rgbColor) < 255)) {
 
586
            m_flags |= DirtyBlending;
 
587
        }
563
588
        m_color = rgbColor;
564
589
        update();
565
590
        Q_EMIT colorChanged();
571
596
    Q_UNUSED(data);
572
597
 
573
598
    const QSizeF itemSize(width(), height());
574
 
    if (itemSize.isEmpty() || m_thickness == 0) {
 
599
    if (itemSize.isEmpty() || m_thickness == 0 || qAlpha(m_color) == 0) {
575
600
        delete oldNode;
576
601
        return NULL;
577
602
    }
581
606
 
582
607
    if (oldNode) {
583
608
        frameNode = static_cast<UCFrameNode*>(oldNode->firstChild());
 
609
        if (m_flags & DirtyBlending) {
 
610
            frameNode->updateBlending(qAlpha(m_color) < 255);
 
611
        }
584
612
        frameCornerNode = static_cast<UCFrameCornerNode*>(oldNode->lastChild());
585
613
        if (m_flags & DirtyShape) {
586
614
            frameCornerNode->setShape(static_cast<Shape>(m_shape));
590
618
        }
591
619
    } else {
592
620
        oldNode = new QSGNode;
593
 
        frameNode = new UCFrameNode;
 
621
        frameNode = new UCFrameNode(qAlpha(m_color) < 255);
594
622
        frameCornerNode = new UCFrameCornerNode(static_cast<Shape>(m_shape), m_radius > 0);
595
623
        oldNode->appendChildNode(frameNode);
596
624
        oldNode->appendChildNode(frameCornerNode);