Marble

StackedTile.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2006-2023 Torsten Rahn <tackat@kde.org>
4// SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
5// SPDX-FileCopyrightText: 2008-2010 Jens-Michael Hoffmann <jensmh@gmx.de>
6// SPDX-FileCopyrightText: 2010-2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
7//
8
9#include "StackedTile.h"
10
11#include "MarbleDebug.h"
12#include "TextureTile.h"
13
14using namespace Marble;
15
16static const uint **jumpTableFromQImage32(const QImage &img)
17{
18 if (img.depth() != 48 && img.depth() != 32)
19 return nullptr;
20
21 const int height = img.height();
22 const int bpl = img.bytesPerLine() / 4;
23 const uint *data = reinterpret_cast<const QRgb *>(img.bits());
24 const uint **jumpTable = new const uint *[height];
25
26 for (int y = 0; y < height; ++y) {
27 jumpTable[y] = data;
28 data += bpl;
29 }
30
31 return jumpTable;
32}
33
34static const uchar **jumpTableFromQImage8(const QImage &img)
35{
36 if (img.depth() != 8 && img.depth() != 1)
37 return nullptr;
38
39 const int height = img.height();
40 const int bpl = img.bytesPerLine();
41 const uchar *data = img.bits();
42 const uchar **jumpTable = new const uchar *[height];
43
44 for (int y = 0; y < height; ++y) {
45 jumpTable[y] = data;
46 data += bpl;
47 }
48
49 return jumpTable;
50}
51
52// return channelwise average of colors c1 and c2
53static inline uint colorMix50(uint c1, uint c2)
54{
55 return (((c1 ^ c2) & 0xfefefefeUL) >> 1) + (c1 & c2);
56}
57
58static inline uint colorMix75(uint c1, uint c2)
59{
60 return colorMix50(c1, colorMix50(c1, c2)); // 75% c1
61}
62
63static inline uint colorMix25(uint c1, uint c2)
64{
65 return colorMix50(colorMix50(c1, c2), c2); // 25% c1
66}
67
68StackedTile::StackedTile(const TileId &id, const QImage &resultImage, QList<QSharedPointer<TextureTile>> const &tiles)
69 : Tile(id)
70 , m_resultImage(resultImage)
71 , m_depth(resultImage.depth())
72 , m_isGrayscale(resultImage.isGrayscale())
73 , m_tiles(tiles)
74 , jumpTable8(jumpTableFromQImage8(m_resultImage))
75 , jumpTable32(jumpTableFromQImage32(m_resultImage))
76 , m_byteCount(calcByteCount(resultImage, tiles))
77 , m_isUsed(false)
78{
79 Q_ASSERT(!tiles.isEmpty());
80
81 if (jumpTable32 == nullptr && jumpTable8 == nullptr) {
82 qWarning() << "Color depth" << m_depth << " is not supported.";
83 }
84}
85
86StackedTile::~StackedTile()
87{
88 delete[] jumpTable32;
89 delete[] jumpTable8;
90}
91
92uint StackedTile::pixel(int x, int y) const
93{
94 if (m_depth == 32 && !m_isGrayscale)
95 return (jumpTable32)[y][x];
96
97 if (m_depth == 8) {
98 if (m_isGrayscale)
99 return (jumpTable8)[y][x];
100 else
101 return m_resultImage.color((jumpTable8)[y][x]);
102 }
103
104 if (m_depth == 1 && !m_isGrayscale)
105 return m_resultImage.color((jumpTable8)[y][x / 8] >> 7);
106
107 return m_resultImage.pixel(x, y);
108}
109
110#define CHEAPHIGH
111#ifdef CHEAPHIGH
112
113uint StackedTile::pixelF(qreal x, qreal y, const QRgb &topLeftValue) const
114{
115 // Bilinear interpolation to determine the color of a subpixel
116 int iX = (int)(x);
117 int iY = (int)(y);
118
119 qreal fY = 8 * (y - iY);
120
121 // Interpolation in y-direction
122 if ((iY + 1) < m_resultImage.height()) {
123 QRgb bottomLeftValue = pixel(iX, iY + 1);
124
125 QRgb leftValue;
126 if (fY < 1)
127 leftValue = topLeftValue;
128 else if (fY < 3)
129 leftValue = colorMix75(topLeftValue, bottomLeftValue);
130 else if (fY < 5)
131 leftValue = colorMix50(topLeftValue, bottomLeftValue);
132 else if (fY < 7)
133 leftValue = colorMix25(topLeftValue, bottomLeftValue);
134 else
135 leftValue = bottomLeftValue;
136
137 // Interpolation in x-direction
138 if (iX + 1 < m_resultImage.width()) {
139 qreal fX = 8 * (x - iX);
140
141 QRgb topRightValue = pixel(iX + 1, iY);
142 QRgb bottomRightValue = pixel(iX + 1, iY + 1);
143
144 QRgb rightValue;
145 if (fY < 1)
146 rightValue = topRightValue;
147 else if (fY < 3)
148 rightValue = colorMix75(topRightValue, bottomRightValue);
149 else if (fY < 5)
150 rightValue = colorMix50(topRightValue, bottomRightValue);
151 else if (fY < 7)
152 rightValue = colorMix25(topRightValue, bottomRightValue);
153 else
154 rightValue = bottomRightValue;
155
156 QRgb averageValue;
157
158 if (fX < 1)
159 averageValue = leftValue;
160 else if (fX < 3)
161 averageValue = colorMix75(leftValue, rightValue);
162 else if (fX < 5)
163 averageValue = colorMix50(leftValue, rightValue);
164 else if (fX < 7)
165 averageValue = colorMix25(leftValue, rightValue);
166 else
167 averageValue = rightValue;
168
169 return averageValue;
170 } else {
171 return leftValue;
172 }
173 } else {
174 // Interpolation in x-direction
175 if (iX + 1 < m_resultImage.width()) {
176 qreal fX = 8 * (x - iX);
177
178 if (fX == 0)
179 return topLeftValue;
180
181 QRgb topRightValue = pixel(iX + 1, iY);
182
183 QRgb topValue;
184 if (fX < 1)
185 topValue = topLeftValue;
186 else if (fX < 3)
187 topValue = colorMix75(topLeftValue, topRightValue);
188 else if (fX < 5)
189 topValue = colorMix50(topLeftValue, topRightValue);
190 else if (fX < 7)
191 topValue = colorMix25(topLeftValue, topRightValue);
192 else
193 topValue = topRightValue;
194
195 return topValue;
196 }
197 }
198
199 return topLeftValue;
200}
201
202#else
203
204uint StackedTile::pixelF(qreal x, qreal y, const QRgb &topLeftValue) const
205{
206 // Bilinear interpolation to determine the color of a subpixel
207
208 int iX = (int)(x);
209 int iY = (int)(y);
210
211 qreal fY = y - iY;
212
213 // Interpolation in y-direction
214 if ((iY + 1) < m_resultImage.height()) {
215 QRgb bottomLeftValue = pixel(iX, iY + 1);
216 // blending the color values of the top left and bottom left point
217 qreal ml_red = (1.0 - fY) * qRed(topLeftValue) + fY * qRed(bottomLeftValue);
218 qreal ml_green = (1.0 - fY) * qGreen(topLeftValue) + fY * qGreen(bottomLeftValue);
219 qreal ml_blue = (1.0 - fY) * qBlue(topLeftValue) + fY * qBlue(bottomLeftValue);
220
221 // Interpolation in x-direction
222 if (iX + 1 < m_resultImage.width()) {
223 qreal fX = x - iX;
224
225 QRgb topRightValue = pixel(iX + 1, iY);
226 QRgb bottomRightValue = pixel(iX + 1, iY + 1);
227
228 // blending the color values of the top right and bottom right point
229 qreal mr_red = (1.0 - fY) * qRed(topRightValue) + fY * qRed(bottomRightValue);
230 qreal mr_green = (1.0 - fY) * qGreen(topRightValue) + fY * qGreen(bottomRightValue);
231 qreal mr_blue = (1.0 - fY) * qBlue(topRightValue) + fY * qBlue(bottomRightValue);
232
233 // blending the color values of the resulting middle left
234 // and middle right points
235 int mm_red = (int)((1.0 - fX) * ml_red + fX * mr_red);
236 int mm_green = (int)((1.0 - fX) * ml_green + fX * mr_green);
237 int mm_blue = (int)((1.0 - fX) * ml_blue + fX * mr_blue);
238
239 return qRgb(mm_red, mm_green, mm_blue);
240 } else {
241 return qRgb(ml_red, ml_green, ml_blue);
242 }
243 } else {
244 // Interpolation in x-direction
245 if (iX + 1 < m_resultImage.width()) {
246 qreal fX = x - iX;
247
248 if (fX == 0.0)
249 return topLeftValue;
250
251 QRgb topRightValue = pixel(iX + 1, iY);
252 // blending the color values of the top left and top right point
253 int tm_red = (int)((1.0 - fX) * qRed(topLeftValue) + fX * qRed(topRightValue));
254 int tm_green = (int)((1.0 - fX) * qGreen(topLeftValue) + fX * qGreen(topRightValue));
255 int tm_blue = (int)((1.0 - fX) * qBlue(topLeftValue) + fX * qBlue(topRightValue));
256
257 return qRgb(tm_red, tm_green, tm_blue);
258 }
259 }
260
261 return topLeftValue;
262}
263
264#endif
265
266int StackedTile::calcByteCount(const QImage &resultImage, const QList<QSharedPointer<TextureTile>> &tiles)
267{
268 int byteCount = resultImage.sizeInBytes();
269
270 QList<QSharedPointer<TextureTile>>::const_iterator pos = tiles.constBegin();
271 QList<QSharedPointer<TextureTile>>::const_iterator const end = tiles.constEnd();
272 for (; pos != end; ++pos)
273 byteCount += (*pos)->byteCount();
274
275 return byteCount;
276}
277
278void StackedTile::setUsed(bool used)
279{
280 m_isUsed = used;
281}
282
283bool StackedTile::used() const
284{
285 return m_isUsed;
286}
287
288uint StackedTile::pixelF(qreal x, qreal y) const
289{
290 int iX = (int)(x);
291 int iY = (int)(y);
292
293 QRgb topLeftValue = pixel(iX, iY);
294
295 return pixelF(x, y, topLeftValue);
296}
297
298int StackedTile::depth() const
299{
300 return m_depth;
301}
302
303int StackedTile::byteCount() const
304{
305 return m_byteCount;
306}
307
309{
310 return m_tiles;
311}
312
314{
315 return &m_resultImage;
316}
uint pixelF(qreal x, qreal y) const
Returns the color value of the result tile at a given floating point position.
QList< QSharedPointer< TextureTile > > tiles() const
Returns the stack of Tiles.
QImage const * resultImage() const
Returns the QImage that describes the merged stack of Tiles.
uint pixel(int x, int y) const
Returns the color value of the result tile at the given integer position.
A class that resembles a tile (then it is extended to TextureTile or Vectortile).
Definition Tile.h:43
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
Binds a QML item to a specific geodetic location in screen coordinates.
uchar * bits()
qsizetype bytesPerLine() const const
QRgb color(int i) const const
int depth() const const
int height() const const
QRgb pixel(const QPoint &position) const const
qsizetype sizeInBytes() const const
int width() const const
const_iterator constBegin() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 8 2024 12:02:44 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.