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
34
35static const uchar **jumpTableFromQImage8( const QImage &img )
36{
37 if ( img.depth() != 8 && img.depth() != 1 )
38 return nullptr;
39
40 const int height = img.height();
41 const int bpl = img.bytesPerLine();
42 const uchar *data = img.bits();
43 const uchar **jumpTable = new const uchar*[height];
44
45 for ( int y = 0; y < height; ++y ) {
46 jumpTable[ y ] = data;
47 data += bpl;
48 }
49
50 return jumpTable;
51}
52
53// return channelwise average of colors c1 and c2
54static inline uint colorMix50(uint c1, uint c2)
55{
56 return (((c1 ^ c2) & 0xfefefefeUL) >> 1) + (c1 & c2);
57}
58
59static inline uint colorMix75(uint c1, uint c2)
60{
61 return colorMix50(c1, colorMix50(c1, c2)); // 75% c1
62}
63
64static inline uint colorMix25(uint c1, uint c2)
65{
66 return colorMix50(colorMix50(c1, c2), c2 ); // 25% c1
67}
68
69StackedTile::StackedTile( const TileId &id, const QImage &resultImage, QVector<QSharedPointer<TextureTile> > const &tiles ) :
70 Tile( id ),
71 m_resultImage( resultImage ),
72 m_depth( resultImage.depth() ),
73 m_isGrayscale( resultImage.isGrayscale() ),
74 m_tiles( tiles ),
75 jumpTable8( jumpTableFromQImage8( m_resultImage ) ),
76 jumpTable32( jumpTableFromQImage32( m_resultImage ) ),
77 m_byteCount( calcByteCount( resultImage, tiles ) ),
78 m_isUsed( false )
79{
80 Q_ASSERT( !tiles.isEmpty() );
81
82 if ( jumpTable32 == nullptr && jumpTable8 == nullptr ) {
83 qWarning() << "Color depth" << m_depth << " is not supported.";
84 }
85}
86
87StackedTile::~StackedTile()
88{
89 delete [] jumpTable32;
90 delete [] jumpTable8;
91}
92
93uint StackedTile::pixel( int x, int y ) const
94{
95 if ( m_depth == 32 && !m_isGrayscale )
96 return (jumpTable32)[y][x];
97
98 if ( m_depth == 8 ) {
99 if ( m_isGrayscale )
100 return (jumpTable8)[y][x];
101 else
102 return m_resultImage.color( (jumpTable8)[y][x] );
103 }
104
105 if ( m_depth == 1 && !m_isGrayscale )
106 return m_resultImage.color((jumpTable8)[y][x/8] >> 7);
107
108 return m_resultImage.pixel( x, y );
109}
110
111#define CHEAPHIGH
112#ifdef CHEAPHIGH
113
114uint StackedTile::pixelF(qreal x, qreal y, const QRgb& topLeftValue) const
115{
116 // Bilinear interpolation to determine the color of a subpixel
117 int iX = (int)(x);
118 int iY = (int)(y);
119
120 qreal fY = 8 * (y - iY);
121
122 // Interpolation in y-direction
123 if ((iY + 1) < m_resultImage.height())
124 {
125 QRgb bottomLeftValue = pixel(iX, iY + 1);
126
127 QRgb leftValue;
128 if (fY < 1)
129 leftValue = topLeftValue;
130 else if (fY < 3)
131 leftValue = colorMix75( topLeftValue, bottomLeftValue);
132 else if (fY < 5)
133 leftValue = colorMix50( topLeftValue, bottomLeftValue);
134 else if (fY < 7)
135 leftValue = colorMix25( topLeftValue, bottomLeftValue);
136 else
137 leftValue = bottomLeftValue;
138
139 // Interpolation in x-direction
140 if (iX + 1 < m_resultImage.width())
141 {
142 qreal fX = 8 * (x - iX);
143
144 QRgb topRightValue = pixel(iX + 1, iY);
145 QRgb bottomRightValue = pixel(iX + 1, iY + 1);
146
147 QRgb rightValue;
148 if (fY < 1)
149 rightValue = topRightValue;
150 else if (fY < 3)
151 rightValue = colorMix75( topRightValue, bottomRightValue);
152 else if (fY < 5)
153 rightValue = colorMix50( topRightValue, bottomRightValue);
154 else if (fY < 7)
155 rightValue = colorMix25( topRightValue, bottomRightValue);
156 else
157 rightValue = bottomRightValue;
158
159
160 QRgb averageValue;
161
162 if (fX < 1)
163 averageValue = leftValue;
164 else if (fX < 3)
165 averageValue = colorMix75( leftValue, rightValue);
166 else if (fX < 5)
167 averageValue = colorMix50( leftValue, rightValue);
168 else if (fX < 7)
169 averageValue = colorMix25( leftValue, rightValue);
170 else
171 averageValue = rightValue;
172
173 return averageValue;
174 }
175 else {
176 return leftValue;
177 }
178 }
179 else {
180 // Interpolation in x-direction
181 if ( iX + 1 < m_resultImage.width() ) {
182
183 qreal fX = 8 * (x - iX);
184
185 if ( fX == 0 )
186 return topLeftValue;
187
188 QRgb topRightValue = pixel( iX + 1, iY );
189
190 QRgb topValue;
191 if (fX < 1)
192 topValue = topLeftValue;
193 else if (fX < 3)
194 topValue = colorMix75( topLeftValue, topRightValue);
195 else if (fX < 5)
196 topValue = colorMix50( topLeftValue, topRightValue);
197 else if (fX < 7)
198 topValue = colorMix25( topLeftValue, topRightValue);
199 else
200 topValue = topRightValue;
201
202 return topValue;
203 }
204 }
205
206 return topLeftValue;
207}
208
209#else
210
211uint StackedTile::pixelF( qreal x, qreal y, const QRgb& topLeftValue ) const
212{
213 // Bilinear interpolation to determine the color of a subpixel
214
215 int iX = (int)(x);
216 int iY = (int)(y);
217
218 qreal fY = y - iY;
219
220 // Interpolation in y-direction
221 if ( ( iY + 1 ) < m_resultImage.height() ) {
222
223 QRgb bottomLeftValue = pixel( iX, iY + 1 );
224 // blending the color values of the top left and bottom left point
225 qreal ml_red = ( 1.0 - fY ) * qRed ( topLeftValue ) + fY * qRed ( bottomLeftValue );
226 qreal ml_green = ( 1.0 - fY ) * qGreen( topLeftValue ) + fY * qGreen( bottomLeftValue );
227 qreal ml_blue = ( 1.0 - fY ) * qBlue ( topLeftValue ) + fY * qBlue ( bottomLeftValue );
228
229 // Interpolation in x-direction
230 if ( iX + 1 < m_resultImage.width() ) {
231
232 qreal fX = x - iX;
233
234 QRgb topRightValue = pixel( iX + 1, iY );
235 QRgb bottomRightValue = pixel( iX + 1, iY + 1 );
236
237 // blending the color values of the top right and bottom right point
238 qreal mr_red = ( 1.0 - fY ) * qRed ( topRightValue ) + fY * qRed ( bottomRightValue );
239 qreal mr_green = ( 1.0 - fY ) * qGreen( topRightValue ) + fY * qGreen( bottomRightValue );
240 qreal mr_blue = ( 1.0 - fY ) * qBlue ( topRightValue ) + fY * qBlue ( bottomRightValue );
241
242 // blending the color values of the resulting middle left
243 // and middle right points
244 int mm_red = (int)( ( 1.0 - fX ) * ml_red + fX * mr_red );
245 int mm_green = (int)( ( 1.0 - fX ) * ml_green + fX * mr_green );
246 int mm_blue = (int)( ( 1.0 - fX ) * ml_blue + fX * mr_blue );
247
248 return qRgb( mm_red, mm_green, mm_blue );
249 }
250 else {
251 return qRgb( ml_red, ml_green, ml_blue );
252 }
253 }
254 else {
255 // Interpolation in x-direction
256 if ( iX + 1 < m_resultImage.width() ) {
257
258 qreal fX = x - iX;
259
260 if ( fX == 0.0 )
261 return topLeftValue;
262
263 QRgb topRightValue = pixel( iX + 1, iY );
264 // blending the color values of the top left and top right point
265 int tm_red = (int)( ( 1.0 - fX ) * qRed ( topLeftValue ) + fX * qRed ( topRightValue ) );
266 int tm_green = (int)( ( 1.0 - fX ) * qGreen( topLeftValue ) + fX * qGreen( topRightValue ) );
267 int tm_blue = (int)( ( 1.0 - fX ) * qBlue ( topLeftValue ) + fX * qBlue ( topRightValue ) );
268
269 return qRgb( tm_red, tm_green, tm_blue );
270 }
271 }
272
273 return topLeftValue;
274}
275
276#endif
277
278int StackedTile::calcByteCount( const QImage &resultImage, const QVector<QSharedPointer<TextureTile> > &tiles )
279{
280 int byteCount = resultImage.sizeInBytes();
281
282 QVector<QSharedPointer<TextureTile> >::const_iterator pos = tiles.constBegin();
283 QVector<QSharedPointer<TextureTile> >::const_iterator const end = tiles.constEnd();
284 for (; pos != end; ++pos )
285 byteCount += (*pos)->byteCount();
286
287 return byteCount;
288}
289
290void StackedTile::setUsed( bool used )
291{
292 m_isUsed = used;
293}
294
295bool StackedTile::used() const
296{
297 return m_isUsed;
298}
299
300uint StackedTile::pixelF( qreal x, qreal y ) const
301{
302 int iX = (int)(x);
303 int iY = (int)(y);
304
305 QRgb topLeftValue = pixel( iX, iY );
306
307 return pixelF( x, y, topLeftValue );
308}
309
310int StackedTile::depth() const
311{
312 return m_depth;
313}
314
315int StackedTile::byteCount() const
316{
317 return m_byteCount;
318}
319
321{
322 return m_tiles;
323}
324
326{
327 return &m_resultImage;
328}
329
QVector< QSharedPointer< TextureTile > > tiles() const
Returns the stack of Tiles.
uint pixelF(qreal x, qreal y) const
Returns the color value of the result tile at a given floating point position.
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
const QList< QKeySequence > & end()
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 Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.