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 "MarbleGlobal.h"
9#include "SunLocator.h"
10#include "TextureTile.h"
11#include "TileLoaderHelper.h"
12
13#include <QColor>
14#include <QImage>
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() = default;
30
31void SunLightBlending::blend(QImage *const tileImage, TextureTile const *const top) const
32{
33 if (tileImage->depth() != 32)
34 return;
35
36 // TODO add support for 8-bit maps?
37 // add sun shading
38 const TileId id = top->id();
39 const qreal global_width = tileImage->width() * TileLoaderHelper::levelToColumn(m_levelZeroColumns, id.zoomLevel());
40 const qreal global_height = tileImage->height() * TileLoaderHelper::levelToRow(m_levelZeroRows, id.zoomLevel());
41 const qreal lon_scale = 2 * M_PI / global_width;
42 const qreal lat_scale = -M_PI / global_height;
43 const int tileHeight = tileImage->height();
44 const int tileWidth = tileImage->width();
45
46 // First we determine the supporting point interval for the interpolation.
47 const int n = maxDivisor(30, tileWidth);
48 const int ipRight = n * (int)(tileWidth / n);
49
50 const QImage *nighttile = top->image();
51
52 for (int cur_y = 0; cur_y < tileHeight; ++cur_y) {
53 const qreal lat = lat_scale * (id.y() * tileHeight + cur_y) - 0.5 * M_PI;
54 const qreal a = sin((lat + DEG2RAD * m_sunLocator->getLat()) / 2.0);
55 const qreal c = cos(lat) * cos(-DEG2RAD * m_sunLocator->getLat());
56
57 QRgb *scanline = (QRgb *)tileImage->scanLine(cur_y);
58 const QRgb *nscanline = (QRgb *)nighttile->scanLine(cur_y);
59
60 qreal lastShade = -10.0;
61
62 int cur_x = 0;
63
64 while (cur_x < tileWidth) {
65 const bool interpolate = (cur_x != 0 && cur_x < ipRight && cur_x + n < tileWidth);
66
67 qreal shade = 0;
68
69 if (interpolate) {
70 const int check = cur_x + n;
71 const qreal checklon = lon_scale * (id.x() * tileWidth + check);
72 shade = m_sunLocator->shading(checklon, a, c);
73
74 // if the shading didn't change across the interpolation
75 // interval move on and don't change anything.
76 if (shade == lastShade && shade == 1.0) {
77 scanline += n;
78 nscanline += n;
79 cur_x += n;
80 continue;
81 }
82 if (shade == lastShade && shade == 0.0) {
83 for (int t = 0; t < n; ++t) {
84 SunLocator::shadePixelComposite(*scanline, *nscanline, shade);
85 ++scanline;
86 ++nscanline;
87 }
88 cur_x += n;
89 continue;
90 }
91
92 qreal lon = lon_scale * (id.x() * tileWidth + cur_x);
93 for (int t = 0; t < n; ++t) {
94 shade = m_sunLocator->shading(lon, a, c);
95 SunLocator::shadePixelComposite(*scanline, *nscanline, shade);
96 ++scanline;
97 ++nscanline;
98 lon += lon_scale;
99 }
100 cur_x += n;
101 }
102
103 else {
104 // Make sure we don't exceed the image memory
105 if (cur_x < tileWidth) {
106 qreal lon = lon_scale * (id.x() * tileWidth + cur_x);
107 shade = m_sunLocator->shading(lon, a, c);
108 SunLocator::shadePixelComposite(*scanline, *nscanline, shade);
109 ++scanline;
110 ++nscanline;
111 ++cur_x;
112 }
113 }
114 lastShade = shade;
115 }
116 }
117}
118
119void SunLightBlending::setLevelZeroLayout(int levelZeroColumns, int levelZeroRows)
120{
121 m_levelZeroColumns = levelZeroColumns;
122 m_levelZeroRows = levelZeroRows;
123}
124
125// TODO: This should likely go into a math class in the future ...
126int SunLightBlending::maxDivisor(int maximum, int fullLength)
127{
128 // Find the optimal interpolation interval n for the
129 // current image canvas width
130 int best = 2;
131
132 int nEvalMin = fullLength;
133 for (int it = 1; it <= maximum; ++it) {
134 // The optimum is the interval which results in the least amount
135 // supporting points taking into account the rest which can't
136 // get used for interpolation.
137 int nEval = fullLength / it + fullLength % it;
138 if (nEval < nEvalMin) {
139 nEvalMin = nEval;
140 best = it;
141 }
142 }
143 return best;
144}
145
146}
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 Fri Nov 8 2024 12:02:42 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.