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