[Marble-devel] [PATCH 05/13] Implement sun light blending with citylights theme as Blending sub class.

Jens-Michael Hoffmann jensmh at gmx.de
Tue Mar 30 20:31:09 CEST 2010


Implement sun light blending with citylights theme as Blending sub class.

As a side effect a lot of stuff could be removed from MergedLayerDecorator.
However there are some regressions at the moment:
- the blending is no longer available on celestial bodies other than earth,
- is only possible with citylights theme (no plain darkening),
- is always active (cannot be turned off),
- only support current (and not arbitrary) date and time,
- centering the sun and following time source (with different speeds) does
  no longer work.
---
 marble/data/maps/earth/bluemarble/bluemarble.dgml |    6 +
 marble/src/lib/BlendingFactory.cpp                |    2 +
 marble/src/lib/CMakeLists.txt                     |    1 +
 marble/src/lib/MergedLayerDecorator.cpp           |  241 +--------------------
 marble/src/lib/MergedLayerDecorator.h             |   19 +--
 marble/src/lib/blendings/SunLightBlending.cpp     |  207 ++++++++++++++++++
 marble/src/lib/blendings/SunLightBlending.h       |   45 ++++
 7 files changed, 266 insertions(+), 255 deletions(-)
 create mode 100644 marble/src/lib/blendings/SunLightBlending.cpp
 create mode 100644 marble/src/lib/blendings/SunLightBlending.h

diff --git a/marble/data/maps/earth/bluemarble/bluemarble.dgml b/marble/data/maps/earth/bluemarble/bluemarble.dgml
index d4c5d5e..6924820 100644
--- a/marble/data/maps/earth/bluemarble/bluemarble.dgml
+++ b/marble/data/maps/earth/bluemarble/bluemarble.dgml
@@ -44,6 +44,12 @@
                     <storageLayout maximumTileLevel="1"/>
                     <blending name="CloudsBlending" />
                 </texture>
+                <texture name="citylights_data">
+                    <sourcedir format="JPG"> earth/citylights </sourcedir>
+                    <installmap> citylights.jpg </installmap>
+                    <storageLayout maximumTileLevel="3"/>
+                    <blending name="SunLightBlending" />
+                </texture>
             </layer>
                             
             <layer name="mwdbii" backend="vector" role="polyline">
diff --git a/marble/src/lib/BlendingFactory.cpp b/marble/src/lib/BlendingFactory.cpp
index c32f11b..c9247a3 100644
--- a/marble/src/lib/BlendingFactory.cpp
+++ b/marble/src/lib/BlendingFactory.cpp
@@ -15,6 +15,7 @@
 
 #include "BlendingFactory.h"
 
+#include "blendings/SunLightBlending.h"
 #include "BlendingAlgorithms.h"
 #include "MarbleDebug.h"
 
@@ -81,6 +82,7 @@ BlendingFactory::BlendingFactory()
 
     // Special purpose blendings
     m_blendings.insert( "CloudsBlending", new CloudsBlending );
+    m_blendings.insert( "SunLightBlending", new SunLightBlending );
 }
 
 }
diff --git a/marble/src/lib/CMakeLists.txt b/marble/src/lib/CMakeLists.txt
index c9a6f31..59e4505 100644
--- a/marble/src/lib/CMakeLists.txt
+++ b/marble/src/lib/CMakeLists.txt
@@ -59,6 +59,7 @@ set(marblewidget_SRCS
     ${geodata_SRCS}
     ${graphicsview_SRCS}
     ${screengraphicsitem_SRCS}
+    blendings/SunLightBlending.cpp
     Blending.cpp
     BlendingAlgorithms.cpp
     BlendingFactory.cpp
diff --git a/marble/src/lib/MergedLayerDecorator.cpp b/marble/src/lib/MergedLayerDecorator.cpp
index daca26c..a846d15 100644
--- a/marble/src/lib/MergedLayerDecorator.cpp
+++ b/marble/src/lib/MergedLayerDecorator.cpp
@@ -17,71 +17,24 @@
 
 #include "MergedLayerDecorator.h"
 
+#include <QtCore/QString>
+#include <QtGui/QImage>
 #include <QtGui/QPainter>
 
-#include "SunLocator.h"
-#include "StackedTileLoader.h"
 #include "global.h"
-#include "MarbleDebug.h"
-#include "GeoSceneDocument.h"
-#include "GeoSceneHead.h"
-#include "GeoSceneMap.h"
-#include "GeoSceneSettings.h"
-#include "GeoSceneTexture.h"
-#include "MapThemeManager.h"
-#include "StackedTile.h"
-#include "TileLoaderHelper.h"
-#include "Planet.h"
 
 using namespace Marble;
 
 MergedLayerDecorator::MergedLayerDecorator( StackedTileLoader * const tileLoader,
                                             SunLocator* sunLocator )
-    : m_tileLoader( tileLoader ),
-      m_tile( 0 ),
+    : m_tile( 0 ),
       m_id(),
-      m_sunLocator( sunLocator ),
-      m_showTileId( false ),
-      m_cityLightsTheme( 0 ),
-      m_cityLightsTextureLayer( 0 )
+      m_showTileId( false )
 {
 }
 
-void MergedLayerDecorator::initCityLights()
-{
-    // look for the texture layers inside the themes
-    // As long as we don't have an Layer Management Class we just lookup 
-    // the name of the layer that has the same name as the theme ID
-
-    mDebug() << Q_FUNC_INFO;
-    m_cityLightsTheme = MapThemeManager::loadMapTheme( "earth/citylights/citylights.dgml" );
-    if (m_cityLightsTheme) {
-        QString cityLightsId = m_cityLightsTheme->head()->theme();
-        m_cityLightsTextureLayer = static_cast<GeoSceneTexture*>(
-            m_cityLightsTheme->map()->layer( cityLightsId )->datasets().first() );
-    }
-}
-
-MergedLayerDecorator::~MergedLayerDecorator()
-{
-    delete m_cityLightsTheme;
-}
-
 void MergedLayerDecorator::paint( const QString& themeId, GeoSceneDocument *mapTheme )
 {
-//     QTime time;
-//     time.start();
-    
-    if ( m_sunLocator->getShow() && mapTheme ) {
-
-        // Initialize citylights layer if it hasn't happened already
-        if ( !m_cityLightsTheme ) {
-            initCityLights();
-        }
-//         QTime time2;
-//         time2.start();
-        paintSunShading();
-    }
     if ( m_showTileId ) {
         paintTileId( themeId );
     }
@@ -97,170 +50,6 @@ bool MergedLayerDecorator::showTileId() const
     return m_showTileId;
 }
 
-StackedTile * MergedLayerDecorator::loadDataset( GeoSceneTexture *textureLayer )
-{
-    const TileId decorationTileId( textureLayer->sourceDir(), m_id.zoomLevel(), m_id.x(), m_id.y());
-    StackedTile * const tile = m_tileLoader->loadTile( decorationTileId, true );
-    tile->setUsed( true );
-    return tile;
-}
-
-void MergedLayerDecorator::paintSunShading()
-{
-    if ( m_tile->depth() != 32 )
-        return;
-
-    // TODO add support for 8-bit maps?
-    // add sun shading
-    const qreal  global_width  = m_tile->width()
-        * TileLoaderHelper::levelToColumn( m_cityLightsTextureLayer->levelZeroColumns(),
-                                           m_id.zoomLevel() );
-    const qreal  global_height = m_tile->height()
-        * TileLoaderHelper::levelToRow( m_cityLightsTextureLayer->levelZeroRows(),
-                                        m_id.zoomLevel() );
-    const qreal lon_scale = 2*M_PI / global_width;
-    const qreal lat_scale = -M_PI / global_height;
-    const int tileHeight = m_tile->height();
-    const int tileWidth = m_tile->width();
-
-    // First we determine the supporting point interval for the interpolation.
-    const int n = maxDivisor( 30, tileWidth );
-    const int ipRight = n * (int)( tileWidth / n );
-
-    //Don't use city lights on non-earth planets!
-    if ( m_sunLocator->getCitylights() && m_sunLocator->planet()->id() == "earth" ) {
-
-        StackedTile * tile = loadDataset( m_cityLightsTextureLayer );
-        if ( tile->state() == StackedTile::TileEmpty )
-            return;
-
-        QImage * nighttile = tile->resultTile();
-
-        for ( int cur_y = 0; cur_y < tileHeight; ++cur_y ) {
-            qreal lat = lat_scale * ( m_id.y() * tileHeight + cur_y ) - 0.5*M_PI;
-            qreal a = sin( ( lat+DEG2RAD * m_sunLocator->getLat() )/2.0 );
-            qreal c = cos(lat)*cos( -DEG2RAD * m_sunLocator->getLat() );
-
-            QRgb* scanline  = (QRgb*)m_tile->scanLine( cur_y );
-            QRgb* nscanline = (QRgb*)nighttile->scanLine( cur_y );
-
-            qreal shade = 0;
-            qreal lastShade = -10.0;
-
-            int cur_x = 0;
-
-            while ( cur_x < tileWidth ) {
-
-                bool interpolate = ( cur_x != 0 && cur_x < ipRight && cur_x + n < tileWidth );
-
-                if ( interpolate ) {
-                    int check = cur_x + n;
-                    qreal checklon   = lon_scale * ( m_id.x() * tileWidth + check );
-                    shade = m_sunLocator->shading( checklon, a, c );
-
-                    // if the shading didn't change across the interpolation
-                    // interval move on and don't change anything.
-                    if ( shade == lastShade && shade == 1.0 ) {
-                        scanline += n;
-                        nscanline += n;
-                        cur_x += n;
-                        continue;
-                    }
-                    if ( shade == lastShade && shade == 0.0 ) {
-                        for ( int t = 0; t < n; ++t ) {
-                            m_sunLocator->shadePixelComposite( *scanline, *nscanline, shade );
-                            ++scanline;
-                            ++nscanline;
-                        }
-                        cur_x += n; 
-                        continue;
-                    }
-                    for ( int t = 0; t < n ; ++t ) {
-                        qreal lon   = lon_scale * ( m_id.x() * tileWidth + cur_x );
-                        shade = m_sunLocator->shading( lon, a, c );
-                        m_sunLocator->shadePixelComposite( *scanline, *nscanline, shade );
-                        ++scanline;
-                        ++nscanline;
-                        ++cur_x;
-                    }
-                }
-
-                else {
-                    // Make sure we don't exceed the image memory
-                    if ( cur_x < tileWidth ) {
-                        qreal lon   = lon_scale * ( m_id.x() * tileWidth + cur_x );
-                        shade = m_sunLocator->shading( lon, a, c );
-                        m_sunLocator->shadePixelComposite( *scanline, *nscanline, shade );
-                        ++scanline;
-                        ++nscanline;
-                        ++cur_x;
-                    }
-                }
-                lastShade = shade;
-            }
-        }
-    } else {
-        for ( int cur_y = 0; cur_y < tileHeight; ++cur_y ) {
-            qreal lat = lat_scale * ( m_id.y() * tileHeight + cur_y ) - 0.5*M_PI;
-            qreal a = sin( (lat+DEG2RAD * m_sunLocator->getLat() )/2.0 );
-            qreal c = cos(lat)*cos( -DEG2RAD * m_sunLocator->getLat() );
-
-            QRgb* scanline = (QRgb*)m_tile->scanLine( cur_y );
-
-            qreal shade = 0;
-            qreal lastShade = -10.0;
-
-            int cur_x = 0;
-
-            while ( cur_x < tileWidth ) {
-
-                bool interpolate = ( cur_x != 0 && cur_x < ipRight && cur_x + n < tileWidth );
-
-                if ( interpolate ) {
-                    int check = cur_x + n;
-                    qreal checklon   = lon_scale * ( m_id.x() * tileWidth + check );
-                    shade = m_sunLocator->shading( checklon, a, c );
-
-                    // if the shading didn't change across the interpolation
-                    // interval move on and don't change anything.
-                    if ( shade == lastShade && shade == 1.0 ) {
-                        scanline += n;
-                        cur_x += n;
-                        continue;
-                    }
-                    if ( shade == lastShade && shade == 0.0 ) {
-                        for ( int t = 0; t < n; ++t ) {
-                            m_sunLocator->shadePixel( *scanline, shade );
-                            ++scanline;
-                        }
-                        cur_x += n; 
-                        continue;
-                    }
-                    for ( int t = 0; t < n ; ++t ) {
-                        qreal lon   = lon_scale * ( m_id.x() * tileWidth + cur_x );
-                        shade = m_sunLocator->shading( lon, a, c );
-                        m_sunLocator->shadePixel( *scanline, shade );
-                        ++scanline;
-                        ++cur_x;
-                    }
-                }
-
-                else {
-                    // Make sure we don't exceed the image memory
-                    if ( cur_x < tileWidth ) {
-                        qreal lon   = lon_scale * ( m_id.x() * tileWidth + cur_x );
-                        shade = m_sunLocator->shading( lon, a, c );
-                        m_sunLocator->shadePixel( *scanline, shade );
-                        ++scanline;
-                        ++cur_x;
-                    }
-                }
-                lastShade = shade;
-            }
-        }
-    }
-}
-
 void MergedLayerDecorator::paintTileId( const QString& themeId )
 {
     QString filename = QString( "%1_%2.jpg" )
@@ -333,26 +122,4 @@ void MergedLayerDecorator::setInfo( TileId const& id )
     m_id = id;
 }
 
-// TODO: This should likely go into a math class in the future ...
-
-int MergedLayerDecorator::maxDivisor( int maximum, int fullLength )
-{
-    // Find the optimal interpolation interval n for the 
-    // current image canvas width
-    int best = 2;
-
-    int  nEvalMin = fullLength;
-    for ( int it = 1; it <= maximum; ++it ) {
-        // The optimum is the interval which results in the least amount
-        // supporting points taking into account the rest which can't 
-        // get used for interpolation.
-        int nEval = fullLength / it + fullLength % it;
-        if ( nEval < nEvalMin ) {
-            nEvalMin = nEval;
-            best = it; 
-        }
-    }
-    return best;
-}
-
 #include "MergedLayerDecorator.moc"
diff --git a/marble/src/lib/MergedLayerDecorator.h b/marble/src/lib/MergedLayerDecorator.h
index d3f45f3..af046b3 100644
--- a/marble/src/lib/MergedLayerDecorator.h
+++ b/marble/src/lib/MergedLayerDecorator.h
@@ -16,21 +16,18 @@
 #ifndef MERGED_LAYER_DECORATOR_H
 #define MERGED_LAYER_DECORATOR_H
 
-#include <QtGui/QImage>
 #include <QtCore/QObject>
 
 #include "TileId.h"
-#include "global.h"
 
+class QImage;
 class QString;
 class QUrl;
 
 namespace Marble
 {
 class GeoSceneDocument;
-class GeoSceneTexture;
 class SunLocator;
-class StackedTile;
 class StackedTileLoader;
 
 class MergedLayerDecorator : public QObject
@@ -39,7 +36,6 @@ class MergedLayerDecorator : public QObject
 	
  public:
     MergedLayerDecorator( StackedTileLoader * const tileLoader, SunLocator* sunLocator );
-    virtual ~MergedLayerDecorator();
 
     // The Parameter themeId is only used for displaying the TileId,
     // which is a debugging feature, therefore at this point QString remains.
@@ -55,24 +51,11 @@ class MergedLayerDecorator : public QObject
  Q_SIGNALS:
     void repaintMap();
 	
- private:
-    StackedTile * loadDataset( GeoSceneTexture *textureLayer );
-    int maxDivisor( int maximum, int fullLength );
-
-    void initCityLights();
-
-    void paintSunShading();
-    void paintClouds();
-	
  protected:
     Q_DISABLE_COPY( MergedLayerDecorator )
-    StackedTileLoader * const m_tileLoader;
     QImage* m_tile;
     TileId m_id;
-    SunLocator* m_sunLocator;
     bool m_showTileId;
-    GeoSceneDocument *m_cityLightsTheme;
-    GeoSceneTexture *m_cityLightsTextureLayer;
 };
 
 }
diff --git a/marble/src/lib/blendings/SunLightBlending.cpp b/marble/src/lib/blendings/SunLightBlending.cpp
new file mode 100644
index 0000000..8debf33
--- /dev/null
+++ b/marble/src/lib/blendings/SunLightBlending.cpp
@@ -0,0 +1,207 @@
+// Copyright 2010 Jens-Michael Hoffmann <jmho at c-xx.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+#include "SunLightBlending.h"
+
+#include "ExtDateTime.h"
+#include "MarbleDebug.h"
+#include "Planet.h"
+#include "SunLocator.h"
+#include "TextureTile.h"
+#include "global.h"
+
+#include <QtGui/QImage>
+
+#include <cmath>
+
+namespace Marble
+{
+
+SunLightBlending::SunLightBlending()
+    : Blending(),
+      m_sunLocator( new SunLocator( new ExtDateTime, new Planet( "earth" )))
+{
+}
+
+SunLightBlending::~SunLightBlending()
+{
+    delete m_sunLocator;
+}
+
+void SunLightBlending::blend( QImage * const bottom, QSharedPointer<TextureTile> const & top ) const
+{
+    QImage const * const topImage = top->image();
+    Q_ASSERT( topImage );
+    Q_ASSERT( bottom->size() == topImage->size() );
+    int const tileWidth = bottom->width();
+    int const tileHeight = bottom->height();
+    mDebug() << "SunLightBlending::blend, tile width/height:" << tileWidth << tileHeight;
+
+    // number of pixels in current zoom level
+    // TODO: fix calculation, take levelZero(Columns|Rows) into account
+    int const globalWidth = tileWidth << top->id().zoomLevel();
+    int const globalHeight = tileHeight << top->id().zoomLevel();
+    mDebug() << "SunLightBlending::blend, global width/height:" << globalWidth << globalHeight;
+
+    qreal const lonScale = 2.0 * M_PI / globalWidth;
+    qreal const latScale = -M_PI / globalHeight;
+
+    m_sunLocator->update();
+    qreal const sunZenithLon = m_sunLocator->getLon() * DEG2RAD;
+    qreal const sunZenithLat = m_sunLocator->getLat() * DEG2RAD;
+    mDebug() << "SunLightBlending::blend, sun zenith lon/lat:" << sunZenithLon << sunZenithLat;
+
+    // First we determine the supporting point interval for the interpolation.
+    int const n = maxDivisor( 30, tileWidth );
+    int const ipRight = n * (int)( tileWidth / n );
+
+    for ( int y = 0; y < tileHeight; ++y ) {
+
+        qreal const lat = latScale * ( top->id().y() * tileHeight + y ) - 0.5 * M_PI;
+        qreal const a = sin(( lat + sunZenithLat ) / 2.0 );
+        qreal const c = cos( lat ) * cos( -sunZenithLat );
+
+        QRgb * bottomScanline = (QRgb*) bottom->scanLine( y );
+        QRgb * topScanline = (QRgb*) topImage->scanLine( y );
+
+        qreal shade = 0.0;
+        qreal lastShade = -10.0;
+
+        int x = 0;
+        while ( x < tileWidth ) {
+            bool const interpolate = ( x != 0 && x < ipRight && x + n < tileWidth );
+            if ( interpolate ) {
+                int const check = x + n;
+                qreal const checkLon = lonScale * ( top->id().x() * tileWidth + check );
+                shade = shading( checkLon - sunZenithLon, a, c );
+
+                // if the shading didn't change across the interpolation
+                // interval move on and don't change anything.
+                if ( shade == lastShade && shade == 1.0 ) {
+                    bottomScanline += n;
+                    topScanline += n;
+                    x += n;
+                    continue;
+                }
+                if ( shade == lastShade && shade == 0.0 ) {
+                    for ( int t = 0; t < n; ++t ) {
+                        shadePixelComposite( *bottomScanline, *topScanline, shade );
+                        ++bottomScanline;
+                        ++topScanline;
+                    }
+                    x += n;
+                    continue;
+                }
+                for ( int t = 0; t < n ; ++t ) {
+                    qreal const lon = lonScale * ( top->id().x() * tileWidth + x );
+                    shade = shading( lon - sunZenithLon, a, c );
+                    shadePixelComposite( *bottomScanline, *topScanline, shade );
+                    ++bottomScanline;
+                    ++topScanline;
+                    ++x;
+                }
+            }
+            else {
+                // Make sure we don't exceed the image memory
+                if ( x < tileWidth ) {
+                    qreal const lon = lonScale * ( top->id().x() * tileWidth + x );
+                    shade = shading( lon - sunZenithLon, a, c );
+                    shadePixelComposite( *bottomScanline, *topScanline, shade );
+                    ++bottomScanline;
+                    ++topScanline;
+                    ++x;
+                }
+            }
+            lastShade = shade;
+        }
+    }
+}
+
+void SunLightBlending::shadePixelComposite( QRgb & bottom, QRgb const top, qreal const brightness ) const
+{
+    if ( brightness > 0.99999 )
+        // daylight - no change
+        return;
+
+    if ( brightness < 0.00001 ) {
+        // night
+        bottom = top;
+    }
+    else {
+        // gradual shadowing
+        int const bottomRed = qRed( bottom );
+        int const bootomGreen = qGreen( bottom );
+        int const bottomBlue = qBlue( bottom );
+
+        int const topRed = qRed( top );
+        int const topGreen = qGreen( top );
+        int const topBlue = qBlue( top );
+
+        bottom = qRgb( (int)( brightness * bottomRed + ( 1.0 - brightness ) * topRed ),
+                       (int)( brightness * bootomGreen + ( 1.0 - brightness ) * topGreen ),
+                       (int)( brightness * bottomBlue + ( 1.0 - brightness ) * topBlue ));
+    }
+}
+
+// deltaLon = lon - sunLon
+qreal SunLightBlending::shading( qreal const deltaLon, qreal const a, qreal const c ) const
+{
+    // haversine formula
+    qreal const b = sin( deltaLon / 2.0 );
+    qreal const h = ( a * a ) + c * ( b * b );
+
+    /*
+      h = 0.0 // directly beneath sun
+      h = 0.5 // sunrise/sunset line
+      h = 1.0 // opposite side of earth to the sun
+      theta = 2*asin(sqrt(h))
+    */
+
+    // this equals 18 deg astronomical twilight and is correct for earth or venus
+    qreal const twilightZone = 0.1;
+
+    qreal brightness;
+    if ( h <= 0.5 - twilightZone / 2.0 )
+        brightness = 1.0;
+    else if ( h >= 0.5 + twilightZone / 2.0 )
+        brightness = 0.0;
+    else
+        brightness = ( 0.5 + twilightZone / 2.0 - h ) / twilightZone;
+
+    return brightness;
+}
+
+// TODO: This should likely go into a math class in the future ...
+int SunLightBlending::maxDivisor( int const maximum, int const fullLength ) const
+{
+    // Find the optimal interpolation interval n for the
+    // current image canvas width
+    int best = 2;
+
+    int nEvalMin = fullLength;
+    for ( int it = 1; it <= maximum; ++it ) {
+        // The optimum is the interval which results in the least amount
+        // supporting points taking into account the rest which can't
+        // get used for interpolation.
+        int nEval = fullLength / it + fullLength % it;
+        if ( nEval < nEvalMin ) {
+            nEvalMin = nEval;
+            best = it;
+        }
+    }
+    return best;
+}
+
+}
diff --git a/marble/src/lib/blendings/SunLightBlending.h b/marble/src/lib/blendings/SunLightBlending.h
new file mode 100644
index 0000000..47ec8c4
--- /dev/null
+++ b/marble/src/lib/blendings/SunLightBlending.h
@@ -0,0 +1,45 @@
+// Copyright 2010 Jens-Michael Hoffmann <jmho at c-xx.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+#ifndef MARBLE_SUN_LIGHT_BLENDING_H
+#define MARBLE_SUN_LIGHT_BLENDING_H
+
+#include <QtCore/QtGlobal>
+#include <QtGui/QColor>
+
+#include "Blending.h"
+
+namespace Marble
+{
+
+class SunLocator;
+
+class SunLightBlending: public Blending
+{
+ public:
+    SunLightBlending();
+    virtual ~SunLightBlending();
+    virtual void blend( QImage * const bottom, QSharedPointer<TextureTile> const & top ) const;
+
+ private:
+    void shadePixelComposite( QRgb & bottom, QRgb const top, qreal const brightness ) const;
+    qreal shading( qreal const deltaLon, qreal const a, qreal const c ) const;
+    int maxDivisor( int const maximum, int const fullLength ) const;
+    SunLocator * const m_sunLocator;
+};
+
+}
+
+#endif
-- 
1.7.0.3



More information about the Marble-devel mailing list