Marble

StackedTile.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2006-2023 Torsten Rahn <[email protected]>
4 // SPDX-FileCopyrightText: 2007 Inge Wallin <[email protected]>
5 // SPDX-FileCopyrightText: 2008-2010 Jens-Michael Hoffmann <[email protected]>
6 // SPDX-FileCopyrightText: 2010-2013 Bernhard Beschow <[email protected]>
7 //
8 
9 #include "StackedTile.h"
10 
11 #include "MarbleDebug.h"
12 #include "TextureTile.h"
13 
14 using namespace Marble;
15 
16 static 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 
35 static 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
54 static inline uint colorMix50(uint c1, uint c2)
55 {
56  return (((c1 ^ c2) & 0xfefefefeUL) >> 1) + (c1 & c2);
57 }
58 
59 static inline uint colorMix75(uint c1, uint c2)
60 {
61  return colorMix50(c1, colorMix50(c1, c2)); // 75% c1
62 }
63 
64 static inline uint colorMix25(uint c1, uint c2)
65 {
66  return colorMix50(colorMix50(c1, c2), c2 ); // 25% c1
67 }
68 
69 StackedTile::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 
87 StackedTile::~StackedTile()
88 {
89  delete [] jumpTable32;
90  delete [] jumpTable8;
91 }
92 
93 uint 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 
114 uint 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 
211 uint 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 
278 int 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 
290 void StackedTile::setUsed( bool used )
291 {
292  m_isUsed = used;
293 }
294 
295 bool StackedTile::used() const
296 {
297  return m_isUsed;
298 }
299 
300 uint 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 
310 int StackedTile::depth() const
311 {
312  return m_depth;
313 }
314 
315 int StackedTile::byteCount() const
316 {
317  return m_byteCount;
318 }
319 
321 {
322  return m_tiles;
323 }
324 
326 {
327  return &m_resultImage;
328 }
329 
qsizetype sizeInBytes() const const
QVector< QSharedPointer< TextureTile > > tiles() const
Returns the stack of Tiles.
int height() const const
int depth() const const
QRgb color(int i) const const
const QImage * resultImage() const
Returns the QImage that describes the merged stack of Tiles.
A class that resembles a tile (then it is extended to TextureTile or Vectortile).
Definition: Tile.h:42
QRgb pixel(int x, int y) const const
uchar * bits()
int bytesPerLine() const const
Binds a QML item to a specific geodetic location in screen coordinates.
uint pixelF(qreal x, qreal y) const
Returns the color value of the result tile at a given floating point position.
const QList< QKeySequence > & end()
uint pixel(int x, int y) const
Returns the color value of the result tile at the given integer position.
Definition: StackedTile.cpp:93
int width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Oct 2 2023 03:52:10 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.