Marble

SunLightBlending.cpp
1 // SPDX-FileCopyrightText: 2010 Jens-Michael Hoffmann <[email protected]>
2 //
3 // SPDX-License-Identifier: LGPL-2.1-or-later
4 
5 #include "SunLightBlending.h"
6 
7 #include "MarbleDebug.h"
8 #include "SunLocator.h"
9 #include "TextureTile.h"
10 #include "TileLoaderHelper.h"
11 #include "MarbleGlobal.h"
12 
13 #include <QImage>
14 #include <QColor>
15 
16 #include <cmath>
17 
18 namespace Marble
19 {
20 
21 SunLightBlending::SunLightBlending( const SunLocator * sunLocator )
22  : Blending(),
23  m_sunLocator( sunLocator ),
24  m_levelZeroColumns( 0 ),
25  m_levelZeroRows( 0 )
26 {
27 }
28 
29 SunLightBlending::~SunLightBlending()
30 {
31 }
32 
33 void SunLightBlending::blend( QImage * const tileImage, TextureTile const * const top ) const
34 {
35  if ( tileImage->depth() != 32 )
36  return;
37 
38  // TODO add support for 8-bit maps?
39  // add sun shading
40  const TileId id = top->id();
41  const qreal global_width = tileImage->width()
42  * TileLoaderHelper::levelToColumn( m_levelZeroColumns, id.zoomLevel() );
43  const qreal global_height = tileImage->height()
44  * TileLoaderHelper::levelToRow( m_levelZeroRows, id.zoomLevel() );
45  const qreal lon_scale = 2*M_PI / global_width;
46  const qreal lat_scale = -M_PI / global_height;
47  const int tileHeight = tileImage->height();
48  const int tileWidth = tileImage->width();
49 
50  // First we determine the supporting point interval for the interpolation.
51  const int n = maxDivisor( 30, tileWidth );
52  const int ipRight = n * (int)( tileWidth / n );
53 
54  const QImage *nighttile = top->image();
55 
56  for ( int cur_y = 0; cur_y < tileHeight; ++cur_y ) {
57  const qreal lat = lat_scale * ( id.y() * tileHeight + cur_y ) - 0.5*M_PI;
58  const qreal a = sin( ( lat+DEG2RAD * m_sunLocator->getLat() )/2.0 );
59  const qreal c = cos(lat)*cos( -DEG2RAD * m_sunLocator->getLat() );
60 
61  QRgb* scanline = (QRgb*)tileImage->scanLine( cur_y );
62  const QRgb* nscanline = (QRgb*)nighttile->scanLine( cur_y );
63 
64  qreal lastShade = -10.0;
65 
66  int cur_x = 0;
67 
68  while ( cur_x < tileWidth ) {
69 
70  const bool interpolate = ( cur_x != 0 && cur_x < ipRight && cur_x + n < tileWidth );
71 
72  qreal shade = 0;
73 
74  if ( interpolate ) {
75  const int check = cur_x + n;
76  const qreal checklon = lon_scale * ( id.x() * tileWidth + check );
77  shade = m_sunLocator->shading( checklon, a, c );
78 
79  // if the shading didn't change across the interpolation
80  // interval move on and don't change anything.
81  if ( shade == lastShade && shade == 1.0 ) {
82  scanline += n;
83  nscanline += n;
84  cur_x += n;
85  continue;
86  }
87  if ( shade == lastShade && shade == 0.0 ) {
88  for ( int t = 0; t < n; ++t ) {
89  SunLocator::shadePixelComposite(*scanline, *nscanline, shade);
90  ++scanline;
91  ++nscanline;
92  }
93  cur_x += n;
94  continue;
95  }
96 
97  qreal lon = lon_scale * (id.x() * tileWidth + cur_x);
98  for ( int t = 0; t < n ; ++t ) {
99  shade = m_sunLocator->shading( lon, a, c );
100  SunLocator::shadePixelComposite(*scanline, *nscanline, shade);
101  ++scanline;
102  ++nscanline;
103  lon += lon_scale;
104  }
105  cur_x += n;
106  }
107 
108  else {
109  // Make sure we don't exceed the image memory
110  if ( cur_x < tileWidth ) {
111  qreal lon = lon_scale * ( id.x() * tileWidth + cur_x );
112  shade = m_sunLocator->shading( lon, a, c );
113  SunLocator::shadePixelComposite(*scanline, *nscanline, shade);
114  ++scanline;
115  ++nscanline;
116  ++cur_x;
117  }
118  }
119  lastShade = shade;
120  }
121  }
122 }
123 
124 void SunLightBlending::setLevelZeroLayout( int levelZeroColumns, int levelZeroRows )
125 {
126  m_levelZeroColumns = levelZeroColumns;
127  m_levelZeroRows = levelZeroRows;
128 }
129 
130 // TODO: This should likely go into a math class in the future ...
131 int SunLightBlending::maxDivisor( int maximum, int fullLength )
132 {
133  // Find the optimal interpolation interval n for the
134  // current image canvas width
135  int best = 2;
136 
137  int nEvalMin = fullLength;
138  for ( int it = 1; it <= maximum; ++it ) {
139  // The optimum is the interval which results in the least amount
140  // supporting points taking into account the rest which can't
141  // get used for interpolation.
142  int nEval = fullLength / it + fullLength % it;
143  if ( nEval < nEvalMin ) {
144  nEvalMin = nEval;
145  best = it;
146  }
147  }
148  return best;
149 }
150 
151 }
int height() const const
int depth() const const
Binds a QML item to a specific geodetic location in screen coordinates.
uchar * scanLine(int i)
KGUIADDONS_EXPORT QColor shade(const QColor &, qreal lumaAmount, qreal chromaAmount=0.0)
int width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Wed Oct 4 2023 04:09:43 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.