File indexing completed on 2024-04-14 03:48:04
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2006-2023 Torsten Rahn <tackat@kde.org> 0004 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org> 0005 // SPDX-FileCopyrightText: 2008-2010 Jens-Michael Hoffmann <jensmh@gmx.de> 0006 // SPDX-FileCopyrightText: 2010-2013 Bernhard Beschow <bbeschow@cs.tu-berlin.de> 0007 // 0008 0009 #include "StackedTile.h" 0010 0011 #include "MarbleDebug.h" 0012 #include "TextureTile.h" 0013 0014 using namespace Marble; 0015 0016 static const uint **jumpTableFromQImage32( const QImage &img ) 0017 { 0018 if ( img.depth() != 48 && img.depth() != 32 ) 0019 return nullptr; 0020 0021 const int height = img.height(); 0022 const int bpl = img.bytesPerLine() / 4; 0023 const uint *data = reinterpret_cast<const QRgb*>(img.bits()); 0024 const uint **jumpTable = new const uint*[height]; 0025 0026 for ( int y = 0; y < height; ++y ) { 0027 jumpTable[ y ] = data; 0028 data += bpl; 0029 } 0030 0031 return jumpTable; 0032 } 0033 0034 0035 static const uchar **jumpTableFromQImage8( const QImage &img ) 0036 { 0037 if ( img.depth() != 8 && img.depth() != 1 ) 0038 return nullptr; 0039 0040 const int height = img.height(); 0041 const int bpl = img.bytesPerLine(); 0042 const uchar *data = img.bits(); 0043 const uchar **jumpTable = new const uchar*[height]; 0044 0045 for ( int y = 0; y < height; ++y ) { 0046 jumpTable[ y ] = data; 0047 data += bpl; 0048 } 0049 0050 return jumpTable; 0051 } 0052 0053 // return channelwise average of colors c1 and c2 0054 static inline uint colorMix50(uint c1, uint c2) 0055 { 0056 return (((c1 ^ c2) & 0xfefefefeUL) >> 1) + (c1 & c2); 0057 } 0058 0059 static inline uint colorMix75(uint c1, uint c2) 0060 { 0061 return colorMix50(c1, colorMix50(c1, c2)); // 75% c1 0062 } 0063 0064 static inline uint colorMix25(uint c1, uint c2) 0065 { 0066 return colorMix50(colorMix50(c1, c2), c2 ); // 25% c1 0067 } 0068 0069 StackedTile::StackedTile( const TileId &id, const QImage &resultImage, QVector<QSharedPointer<TextureTile> > const &tiles ) : 0070 Tile( id ), 0071 m_resultImage( resultImage ), 0072 m_depth( resultImage.depth() ), 0073 m_isGrayscale( resultImage.isGrayscale() ), 0074 m_tiles( tiles ), 0075 jumpTable8( jumpTableFromQImage8( m_resultImage ) ), 0076 jumpTable32( jumpTableFromQImage32( m_resultImage ) ), 0077 m_byteCount( calcByteCount( resultImage, tiles ) ), 0078 m_isUsed( false ) 0079 { 0080 Q_ASSERT( !tiles.isEmpty() ); 0081 0082 if ( jumpTable32 == nullptr && jumpTable8 == nullptr ) { 0083 qWarning() << "Color depth" << m_depth << " is not supported."; 0084 } 0085 } 0086 0087 StackedTile::~StackedTile() 0088 { 0089 delete [] jumpTable32; 0090 delete [] jumpTable8; 0091 } 0092 0093 uint StackedTile::pixel( int x, int y ) const 0094 { 0095 if ( m_depth == 32 && !m_isGrayscale ) 0096 return (jumpTable32)[y][x]; 0097 0098 if ( m_depth == 8 ) { 0099 if ( m_isGrayscale ) 0100 return (jumpTable8)[y][x]; 0101 else 0102 return m_resultImage.color( (jumpTable8)[y][x] ); 0103 } 0104 0105 if ( m_depth == 1 && !m_isGrayscale ) 0106 return m_resultImage.color((jumpTable8)[y][x/8] >> 7); 0107 0108 return m_resultImage.pixel( x, y ); 0109 } 0110 0111 #define CHEAPHIGH 0112 #ifdef CHEAPHIGH 0113 0114 uint StackedTile::pixelF(qreal x, qreal y, const QRgb& topLeftValue) const 0115 { 0116 // Bilinear interpolation to determine the color of a subpixel 0117 int iX = (int)(x); 0118 int iY = (int)(y); 0119 0120 qreal fY = 8 * (y - iY); 0121 0122 // Interpolation in y-direction 0123 if ((iY + 1) < m_resultImage.height()) 0124 { 0125 QRgb bottomLeftValue = pixel(iX, iY + 1); 0126 0127 QRgb leftValue; 0128 if (fY < 1) 0129 leftValue = topLeftValue; 0130 else if (fY < 3) 0131 leftValue = colorMix75( topLeftValue, bottomLeftValue); 0132 else if (fY < 5) 0133 leftValue = colorMix50( topLeftValue, bottomLeftValue); 0134 else if (fY < 7) 0135 leftValue = colorMix25( topLeftValue, bottomLeftValue); 0136 else 0137 leftValue = bottomLeftValue; 0138 0139 // Interpolation in x-direction 0140 if (iX + 1 < m_resultImage.width()) 0141 { 0142 qreal fX = 8 * (x - iX); 0143 0144 QRgb topRightValue = pixel(iX + 1, iY); 0145 QRgb bottomRightValue = pixel(iX + 1, iY + 1); 0146 0147 QRgb rightValue; 0148 if (fY < 1) 0149 rightValue = topRightValue; 0150 else if (fY < 3) 0151 rightValue = colorMix75( topRightValue, bottomRightValue); 0152 else if (fY < 5) 0153 rightValue = colorMix50( topRightValue, bottomRightValue); 0154 else if (fY < 7) 0155 rightValue = colorMix25( topRightValue, bottomRightValue); 0156 else 0157 rightValue = bottomRightValue; 0158 0159 0160 QRgb averageValue; 0161 0162 if (fX < 1) 0163 averageValue = leftValue; 0164 else if (fX < 3) 0165 averageValue = colorMix75( leftValue, rightValue); 0166 else if (fX < 5) 0167 averageValue = colorMix50( leftValue, rightValue); 0168 else if (fX < 7) 0169 averageValue = colorMix25( leftValue, rightValue); 0170 else 0171 averageValue = rightValue; 0172 0173 return averageValue; 0174 } 0175 else { 0176 return leftValue; 0177 } 0178 } 0179 else { 0180 // Interpolation in x-direction 0181 if ( iX + 1 < m_resultImage.width() ) { 0182 0183 qreal fX = 8 * (x - iX); 0184 0185 if ( fX == 0 ) 0186 return topLeftValue; 0187 0188 QRgb topRightValue = pixel( iX + 1, iY ); 0189 0190 QRgb topValue; 0191 if (fX < 1) 0192 topValue = topLeftValue; 0193 else if (fX < 3) 0194 topValue = colorMix75( topLeftValue, topRightValue); 0195 else if (fX < 5) 0196 topValue = colorMix50( topLeftValue, topRightValue); 0197 else if (fX < 7) 0198 topValue = colorMix25( topLeftValue, topRightValue); 0199 else 0200 topValue = topRightValue; 0201 0202 return topValue; 0203 } 0204 } 0205 0206 return topLeftValue; 0207 } 0208 0209 #else 0210 0211 uint StackedTile::pixelF( qreal x, qreal y, const QRgb& topLeftValue ) const 0212 { 0213 // Bilinear interpolation to determine the color of a subpixel 0214 0215 int iX = (int)(x); 0216 int iY = (int)(y); 0217 0218 qreal fY = y - iY; 0219 0220 // Interpolation in y-direction 0221 if ( ( iY + 1 ) < m_resultImage.height() ) { 0222 0223 QRgb bottomLeftValue = pixel( iX, iY + 1 ); 0224 // blending the color values of the top left and bottom left point 0225 qreal ml_red = ( 1.0 - fY ) * qRed ( topLeftValue ) + fY * qRed ( bottomLeftValue ); 0226 qreal ml_green = ( 1.0 - fY ) * qGreen( topLeftValue ) + fY * qGreen( bottomLeftValue ); 0227 qreal ml_blue = ( 1.0 - fY ) * qBlue ( topLeftValue ) + fY * qBlue ( bottomLeftValue ); 0228 0229 // Interpolation in x-direction 0230 if ( iX + 1 < m_resultImage.width() ) { 0231 0232 qreal fX = x - iX; 0233 0234 QRgb topRightValue = pixel( iX + 1, iY ); 0235 QRgb bottomRightValue = pixel( iX + 1, iY + 1 ); 0236 0237 // blending the color values of the top right and bottom right point 0238 qreal mr_red = ( 1.0 - fY ) * qRed ( topRightValue ) + fY * qRed ( bottomRightValue ); 0239 qreal mr_green = ( 1.0 - fY ) * qGreen( topRightValue ) + fY * qGreen( bottomRightValue ); 0240 qreal mr_blue = ( 1.0 - fY ) * qBlue ( topRightValue ) + fY * qBlue ( bottomRightValue ); 0241 0242 // blending the color values of the resulting middle left 0243 // and middle right points 0244 int mm_red = (int)( ( 1.0 - fX ) * ml_red + fX * mr_red ); 0245 int mm_green = (int)( ( 1.0 - fX ) * ml_green + fX * mr_green ); 0246 int mm_blue = (int)( ( 1.0 - fX ) * ml_blue + fX * mr_blue ); 0247 0248 return qRgb( mm_red, mm_green, mm_blue ); 0249 } 0250 else { 0251 return qRgb( ml_red, ml_green, ml_blue ); 0252 } 0253 } 0254 else { 0255 // Interpolation in x-direction 0256 if ( iX + 1 < m_resultImage.width() ) { 0257 0258 qreal fX = x - iX; 0259 0260 if ( fX == 0.0 ) 0261 return topLeftValue; 0262 0263 QRgb topRightValue = pixel( iX + 1, iY ); 0264 // blending the color values of the top left and top right point 0265 int tm_red = (int)( ( 1.0 - fX ) * qRed ( topLeftValue ) + fX * qRed ( topRightValue ) ); 0266 int tm_green = (int)( ( 1.0 - fX ) * qGreen( topLeftValue ) + fX * qGreen( topRightValue ) ); 0267 int tm_blue = (int)( ( 1.0 - fX ) * qBlue ( topLeftValue ) + fX * qBlue ( topRightValue ) ); 0268 0269 return qRgb( tm_red, tm_green, tm_blue ); 0270 } 0271 } 0272 0273 return topLeftValue; 0274 } 0275 0276 #endif 0277 0278 int StackedTile::calcByteCount( const QImage &resultImage, const QVector<QSharedPointer<TextureTile> > &tiles ) 0279 { 0280 int byteCount = resultImage.sizeInBytes(); 0281 0282 QVector<QSharedPointer<TextureTile> >::const_iterator pos = tiles.constBegin(); 0283 QVector<QSharedPointer<TextureTile> >::const_iterator const end = tiles.constEnd(); 0284 for (; pos != end; ++pos ) 0285 byteCount += (*pos)->byteCount(); 0286 0287 return byteCount; 0288 } 0289 0290 void StackedTile::setUsed( bool used ) 0291 { 0292 m_isUsed = used; 0293 } 0294 0295 bool StackedTile::used() const 0296 { 0297 return m_isUsed; 0298 } 0299 0300 uint StackedTile::pixelF( qreal x, qreal y ) const 0301 { 0302 int iX = (int)(x); 0303 int iY = (int)(y); 0304 0305 QRgb topLeftValue = pixel( iX, iY ); 0306 0307 return pixelF( x, y, topLeftValue ); 0308 } 0309 0310 int StackedTile::depth() const 0311 { 0312 return m_depth; 0313 } 0314 0315 int StackedTile::byteCount() const 0316 { 0317 return m_byteCount; 0318 } 0319 0320 QVector<QSharedPointer<TextureTile> > StackedTile::tiles() const 0321 { 0322 return m_tiles; 0323 } 0324 0325 QImage const * StackedTile::resultImage() const 0326 { 0327 return &m_resultImage; 0328 } 0329