Marble

SunLightBlending.cpp
1// SPDX-FileCopyrightText: 2010 Jens-Michael Hoffmann <jmho@c-xx.com>
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
18namespace Marble
19{
20
21SunLightBlending::SunLightBlending( const SunLocator * sunLocator )
22 : Blending(),
23 m_sunLocator( sunLocator ),
24 m_levelZeroColumns( 0 ),
25 m_levelZeroRows( 0 )
26{
27}
28
29SunLightBlending::~SunLightBlending()
30{
31}
32
33void 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
124void 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 ...
131int 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}
KGUIADDONS_EXPORT QColor shade(const QColor &, qreal lumaAmount, qreal chromaAmount=0.0)
Binds a QML item to a specific geodetic location in screen coordinates.
int depth() const const
int height() const const
uchar * scanLine(int i)
int width() 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:16 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.