1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsggradientcache_p.h"
#include <QtGui/private/qdrawhelper_p.h>
#include <QtGui/rhi/qrhi.h>
#include <QtQuick/qsgtexture.h>
#include <QtQuick/private/qsgplaintexture_p.h>
QT_BEGIN_NAMESPACE
static void generateGradientColorTable(const QSGGradientCacheKey &gradient,
uint *colorTable, int size, float opacity)
{
int pos = 0;
const QGradientStops &s = gradient.stops;
Q_ASSERT(!s.isEmpty());
const bool colorInterpolation = true;
uint alpha = qRound(opacity * 256);
uint current_color = ARGB_COMBINE_ALPHA(s[0].second.rgba(), alpha);
qreal incr = 1.0 / qreal(size);
qreal fpos = 1.5 * incr;
colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color));
while (fpos <= s.first().first) {
colorTable[pos] = colorTable[pos - 1];
pos++;
fpos += incr;
}
if (colorInterpolation)
current_color = qPremultiply(current_color);
const int sLast = s.size() - 1;
for (int i = 0; i < sLast; ++i) {
qreal delta = 1/(s[i+1].first - s[i].first);
uint next_color = ARGB_COMBINE_ALPHA(s[i + 1].second.rgba(), alpha);
if (colorInterpolation)
next_color = qPremultiply(next_color);
while (fpos < s[i+1].first && pos < size) {
int dist = int(256 * ((fpos - s[i].first) * delta));
int idist = 256 - dist;
if (colorInterpolation)
colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist));
else
colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)));
++pos;
fpos += incr;
}
current_color = next_color;
}
uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
for ( ; pos < size; ++pos)
colorTable[pos] = last_color;
colorTable[size-1] = last_color;
}
QSGGradientCache::~QSGGradientCache()
{
qDeleteAll(m_textures);
}
QSGGradientCache *QSGGradientCache::cacheForRhi(QRhi *rhi)
{
static QHash<QRhi *, QSGGradientCache *> caches;
auto it = caches.constFind(rhi);
if (it != caches.constEnd())
return *it;
QSGGradientCache *cache = new QSGGradientCache;
rhi->addCleanupCallback([cache](QRhi *rhi) {
caches.remove(rhi);
delete cache;
});
caches.insert(rhi, cache);
return cache;
}
QSGTexture *QSGGradientCache::get(const QSGGradientCacheKey &grad)
{
QSGPlainTexture *tx = m_textures[grad];
if (!tx) {
static const int W = 1024; // texture size is 1024x1
QImage gradTab(W, 1, QImage::Format_RGBA8888_Premultiplied);
if (!grad.stops.isEmpty())
generateGradientColorTable(grad, reinterpret_cast<uint *>(gradTab.bits()), W, 1.0f);
else
gradTab.fill(Qt::black);
tx = new QSGPlainTexture;
tx->setImage(gradTab);
switch (grad.spread) {
case QGradient::PadSpread:
tx->setHorizontalWrapMode(QSGTexture::ClampToEdge);
tx->setVerticalWrapMode(QSGTexture::ClampToEdge);
break;
case QGradient::RepeatSpread:
tx->setHorizontalWrapMode(QSGTexture::Repeat);
tx->setVerticalWrapMode(QSGTexture::Repeat);
break;
case QGradient::ReflectSpread:
tx->setHorizontalWrapMode(QSGTexture::MirroredRepeat);
tx->setVerticalWrapMode(QSGTexture::MirroredRepeat);
break;
default:
qWarning("Unknown gradient spread mode %d", grad.spread);
break;
}
tx->setFiltering(QSGTexture::Linear);
m_textures[grad] = tx;
}
return tx;
}
QT_END_NAMESPACE
|