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

Torsten Rahn tackat at t-online.de
Wed Mar 31 09:36:10 CEST 2010


Wow, I had almost forgotten how scary (but pretty efficient) this optimized piece 
of code was.

Looks good to me. Ship it.



On Dienstag 30 März 2010 20:31:09 Jens-Michael Hoffmann wrote:
> 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





More information about the Marble-devel mailing list