skins/AknSkins/rlpluginsrc/AknsRlEffectPluginBumpMap.cpp
changeset 0 05e9090e2422
equal deleted inserted replaced
-1:000000000000 0:05e9090e2422
       
     1 /*
       
     2 * Copyright (c) 2004-2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Bump-mapping for effects.
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 // INCLUDE FILES
       
    20 #include <e32math.h>
       
    21 
       
    22 #include "AknsRlEffectPluginBumpMap.h"
       
    23 #include "AknsRlEffectUtil.h"
       
    24 
       
    25 // CONSTANTS
       
    26 const TReal KPixelScale = 255.9;
       
    27 
       
    28 // ====================== TEMPLATED IMPL. OF BUMPMAP ===========================
       
    29 /**
       
    30 * Template implementation of BumpMap. Type defines the used data type for
       
    31 * iterating over the bitmap data. X, R, G and B define the used pixel color bit
       
    32 * layout.
       
    33 */
       
    34 template<class Type,TInt X, TInt R, TInt G, TInt B>
       
    35 class AknsRlEffectBumpMap
       
    36     {
       
    37     public:
       
    38     /**
       
    39     * @return KErrNone if processing was ok, something else on error.
       
    40     */
       
    41     static TInt Process( const CFbsBitmap& aTarget,
       
    42                          const CFbsBitmap& aSource,
       
    43                          const TReal aAzimuth,
       
    44                          const TReal aElevation,
       
    45                          const TInt aDepth,
       
    46                          TAknsRlChannelBlendMode aBlendMode,
       
    47                          const TInt aBlendFactor,
       
    48                          TUint8* aGrayscale )
       
    49         {
       
    50         // CFbsBitmap::ScanLineLength returns bytes, determine the scanw when using Type
       
    51         TInt scanW  = CFbsBitmap::ScanLineLength( aTarget.SizeInPixels().iWidth,
       
    52                                                   aTarget.DisplayMode() ) / sizeof(Type);
       
    53         TInt width  = aTarget.SizeInPixels().iWidth;
       
    54         TInt height = aTarget.SizeInPixels().iHeight;
       
    55 
       
    56         TInt grayW = width + 2;
       
    57         TInt grayH = height + 2;
       
    58 
       
    59         TInt x, y;
       
    60 
       
    61         // Step 1: Grayscale the image
       
    62         TInt pitch = scanW - width;
       
    63         // The grayscale buffer has that one pixel extra border
       
    64         TUint8* buf = aGrayscale + grayW + 1;
       
    65         aSource.LockHeap(); // Lock the global bitmap heap
       
    66         Type* dataS = reinterpret_cast<Type*>( aSource.DataAddress() );
       
    67 
       
    68         for( y=0; y < height; y++ )
       
    69             {
       
    70             for( x=0; x < width; x++ )
       
    71                 {
       
    72                 *buf = AknsRlUtil::Grayscale( AknsRlRgb<Type,X,R,G,B>::R8(*dataS),
       
    73                                               AknsRlRgb<Type,X,R,G,B>::G8(*dataS),
       
    74                                               AknsRlRgb<Type,X,R,G,B>::B8(*dataS) );
       
    75                 buf++;
       
    76                 dataS++;
       
    77                 }
       
    78 
       
    79             // Skip possibly trailing pixels on aSource
       
    80             dataS = dataS + pitch;
       
    81             buf = buf + 2;
       
    82             }
       
    83 
       
    84         aSource.UnlockHeap(); // Unlock the global bitmap heap
       
    85 
       
    86         // Next, fill the grayscale 1 pixel border by copying the neighbouring
       
    87         // pixel values
       
    88 
       
    89         // Top row
       
    90         buf = aGrayscale + 1;
       
    91         for( x=1; x < grayW - 2; x++ )
       
    92             {
       
    93             *buf = *( buf + grayW );
       
    94             buf++;
       
    95             }
       
    96 
       
    97         // Bottom row
       
    98         buf = aGrayscale + grayW * (grayH - 1) + 1;
       
    99         for( x=1; x < grayW - 2; x++ )
       
   100             {
       
   101             *buf = *( buf - grayW );
       
   102             buf++;
       
   103             }
       
   104 
       
   105         // Left column
       
   106         buf = aGrayscale + grayW;
       
   107         for( y=1; y < grayH - 2; y++ )
       
   108             {
       
   109             *buf = *( buf + 1 );
       
   110             buf = buf + grayW;
       
   111             }
       
   112 
       
   113         // Right column
       
   114         buf = aGrayscale + 2 * grayW - 1;
       
   115         for( y=1; y < grayH - 2; y++ )
       
   116             {
       
   117             *buf = *( buf - 1 );
       
   118             buf = buf + grayW;
       
   119             }
       
   120 
       
   121         // Top left corner
       
   122         aGrayscale[ 0 ] = aGrayscale[ grayW + 1 ];
       
   123         // Top right corner
       
   124         aGrayscale[ grayW - 1 ] = aGrayscale[ 2 * grayW - 2 ];
       
   125         // Bottom left corner
       
   126         aGrayscale[ (grayH - 1) * grayW ] = aGrayscale[ ((grayH - 2 ) * grayW) + 1];
       
   127         // Bottom right corner
       
   128         aGrayscale[ (grayH * grayW) - 1 ] = aGrayscale[ (grayH - 2) * grayW + grayW - 2 ];
       
   129 
       
   130         // Step 2: Create the bump map by embossing. The embossing routine
       
   131         // follows the ANSI C code from the article "Fast Embossing Effects on
       
   132         // Raster Image Data" by John Schlag, jfs@kerner.com, in "Graphics Gems
       
   133         // IV", Academic Press, 1994
       
   134 
       
   135         // Determine the light direction vector
       
   136         TReal aziRes, eleRes;
       
   137         TInt err;
       
   138 
       
   139         err = Math::Cos(aziRes, aAzimuth);
       
   140         if( KErrNone != err )
       
   141             return err;
       
   142 
       
   143         err = Math::Cos(eleRes, aElevation);
       
   144         if( KErrNone != err )
       
   145             return err;
       
   146 
       
   147         TInt lx = TInt( aziRes * eleRes * KPixelScale );
       
   148 
       
   149         err = Math::Sin(aziRes, aAzimuth);
       
   150         if( KErrNone != err )
       
   151             return err;
       
   152 
       
   153         TInt ly = TInt( aziRes * eleRes * KPixelScale );
       
   154 
       
   155         err = Math::Sin(eleRes, aElevation);
       
   156         if( KErrNone != err )
       
   157             return err;
       
   158 
       
   159         TInt lz = TInt( eleRes * KPixelScale );
       
   160 
       
   161         // Determine a constant z of image surface normal
       
   162         TInt nz = (6 * 255) / aDepth; // Depth always > 0
       
   163         TInt nz2 = nz * nz;
       
   164         TInt nzlz = nz * lz;
       
   165         TInt nx, ny;
       
   166         TInt NdotL;
       
   167         TInt shade, root;
       
   168         TInt r, g, b;
       
   169         TReal sqrt;
       
   170 
       
   171         aTarget.LockHeap( ETrue ); // Lock the global bitmap heap
       
   172         dataS = reinterpret_cast<Type*>( aSource.DataAddress() );
       
   173         Type* dataT = reinterpret_cast<Type*>( aTarget.DataAddress() );
       
   174 
       
   175         // The grayscale buffer has that one pixel extra border
       
   176         buf = aGrayscale + grayW + 1;
       
   177 
       
   178         // We can process the whole source image directly because the
       
   179         // grayscale image has 1 pixel extra border (convolution can refer
       
   180         // outside the source image dimensions).
       
   181         for(y=0; y < height; y++)
       
   182             {
       
   183             for(x=0; x < width; x++)
       
   184                 {
       
   185                 // Do embossing
       
   186                 nx = *(buf - grayW - 1) + *(buf - 1) + *(buf + grayW - 1) -
       
   187                      *(buf - grayW + 1) - *(buf + 1) - *(buf + grayW + 1);
       
   188                 ny = *(buf + grayW - 1) + *(buf + grayW) + *(buf + grayW + 1) -
       
   189                      *(buf - grayW - 1) - *(buf - grayW) - *(buf - grayW + 1);
       
   190 
       
   191                 if( nx == 0 && ny == 0 )
       
   192                     shade = lz;
       
   193                 else if( (NdotL = nx*lx + ny*ly + nzlz) < 0 )
       
   194                     shade = 0;
       
   195                 else
       
   196                     {
       
   197                     // Note that the error value is ignored because
       
   198                     // nx*nx + ny*ny + nz2 >= 0 always.
       
   199                     Math::Sqrt( sqrt, nx*nx + ny*ny + nz2 );
       
   200                     root = TInt( sqrt );
       
   201                     if( root )
       
   202                         shade = NdotL / root;
       
   203                     else // Square root was rounded to zero
       
   204                         {
       
   205                         // ( nx * nx + ny * ny ) is always >= 0. If aDepth is
       
   206                         // large enough nz2 will be small enough so that sqrt(
       
   207                         // nx*nx + ny*ny + nz2 ) returns < 1.0 and the result
       
   208                         // rounds to zero.
       
   209                         shade = 255;
       
   210                         }
       
   211                     }
       
   212 
       
   213                 if(shade < 0)
       
   214                     shade = 0;
       
   215                 else if(shade > 255)
       
   216                     shade = 255;
       
   217 
       
   218                 // Step 3: Do Channel blending
       
   219                 r = AknsRlChannelBlend::Blend( aBlendMode,
       
   220                                                aBlendFactor,
       
   221                                                AknsRlRgb<Type,X,R,G,B>::R8(*dataS),
       
   222                                                TUint8( shade ));
       
   223                 g = AknsRlChannelBlend::Blend( aBlendMode,
       
   224                                                aBlendFactor,
       
   225                                                AknsRlRgb<Type,X,R,G,B>::G8(*dataS),
       
   226                                                TUint8( shade ));
       
   227                 b = AknsRlChannelBlend::Blend( aBlendMode,
       
   228                                                aBlendFactor,
       
   229                                                AknsRlRgb<Type,X,R,G,B>::B8(*dataS),
       
   230                                                TUint8( shade ));
       
   231 
       
   232                 AknsRlRgb<Type,X,R,G,B>::SetRgb8(dataT, TUint8(r), TUint8(g), TUint8(b));
       
   233 
       
   234                 buf++;
       
   235                 dataS++;
       
   236                 dataT++;
       
   237                 }
       
   238 
       
   239             buf = buf + 2;
       
   240             dataS = dataS + pitch;
       
   241             dataT = dataT + pitch;
       
   242             }
       
   243 
       
   244         aTarget.UnlockHeap( ETrue );
       
   245 
       
   246         return KErrNone;
       
   247         }
       
   248     };
       
   249 
       
   250 // ============================ MEMBER FUNCTIONS ===============================
       
   251 
       
   252 // -----------------------------------------------------------------------------
       
   253 // CAknsRlEffectPluginBumpMap::CAknsRlEffectPluginBumpMap
       
   254 // C++ default constructor can NOT contain any code, that
       
   255 // might leave.
       
   256 // -----------------------------------------------------------------------------
       
   257 //
       
   258 CAknsRlEffectPluginBumpMap::CAknsRlEffectPluginBumpMap()
       
   259     {
       
   260     }
       
   261 
       
   262 // -----------------------------------------------------------------------------
       
   263 // Destructor
       
   264 // -----------------------------------------------------------------------------
       
   265 //
       
   266 CAknsRlEffectPluginBumpMap::~CAknsRlEffectPluginBumpMap()
       
   267     {
       
   268     // The user of this plugin should call deactivate eventually...but we
       
   269     // delete grayscale buffer here too (just in case)
       
   270     delete [] iGrayscale;
       
   271     iContext = NULL;
       
   272     }
       
   273 
       
   274 // -----------------------------------------------------------------------------
       
   275 // CAknsRlEffectPluginBumpMap::EffectUid
       
   276 // -----------------------------------------------------------------------------
       
   277 //
       
   278 TUid CAknsRlEffectPluginBumpMap::EffectUid() const
       
   279     {
       
   280     return TUid::Uid( KAknsRlEffectPluginBumpMapUID );
       
   281     }
       
   282 
       
   283 // -----------------------------------------------------------------------------
       
   284 // CAknsRlEffectPluginBumpMap::Effect
       
   285 // -----------------------------------------------------------------------------
       
   286 //
       
   287 MAknsRlEffect* CAknsRlEffectPluginBumpMap::Effect( const TInt aInterface )
       
   288     {
       
   289     if( aInterface == KAknsRlEffectPluginInterfaceEffect )
       
   290         return this;
       
   291     return NULL;
       
   292     }
       
   293 
       
   294 // -----------------------------------------------------------------------------
       
   295 // CAknsRlEffectPluginBumpMap::InitializeL
       
   296 // -----------------------------------------------------------------------------
       
   297 //
       
   298 void CAknsRlEffectPluginBumpMap::InitializeL()
       
   299     {
       
   300     iContext = NULL;
       
   301     }
       
   302 
       
   303 // -----------------------------------------------------------------------------
       
   304 // CAknsRlEffectPluginBumpMap::Release
       
   305 // -----------------------------------------------------------------------------
       
   306 //
       
   307 void CAknsRlEffectPluginBumpMap::Release()
       
   308     {
       
   309     }
       
   310 
       
   311 // -----------------------------------------------------------------------------
       
   312 // CAknsRlEffectPluginBumpMap::ActivateL
       
   313 // -----------------------------------------------------------------------------
       
   314 //
       
   315 void CAknsRlEffectPluginBumpMap::ActivateL( MAknsRlEffectContext* aContext )
       
   316     {
       
   317     if( !aContext ) // We absolutely need the context
       
   318         {
       
   319         User::Leave( KErrArgument );
       
   320         }
       
   321 
       
   322     iContext = aContext;
       
   323 
       
   324     iAzimuth     = 0.0;
       
   325     iElevation   = 0.59; // ~34 in degrees
       
   326     iDepth       = 10;
       
   327     iBlendMode   = EAknsRlChannelBlendNormal;
       
   328     iBlendFactor = 255;
       
   329 
       
   330     // Because the grayscale image is convoluted we need to create grayscale
       
   331     // image that has extra one pixel border.
       
   332     TSize size = aContext->LayerSize();
       
   333     size.iWidth  = size.iWidth + 2;
       
   334     size.iHeight = size.iHeight + 2;
       
   335 
       
   336     // Calling activate multiple times in row in unlikely but we delete the
       
   337     // grayscale buffer just in case.
       
   338     delete [] iGrayscale;
       
   339     iGrayscale = NULL;
       
   340     iGrayscale = new(ELeave) TUint8[ size.iWidth * size.iHeight ]; //lint !e119 Enough arguments
       
   341     }
       
   342 
       
   343 // -----------------------------------------------------------------------------
       
   344 // CAknsRlEffectPluginBumpMap::Deactivate
       
   345 // -----------------------------------------------------------------------------
       
   346 //
       
   347 void CAknsRlEffectPluginBumpMap::Deactivate()
       
   348     {
       
   349     delete [] iGrayscale;
       
   350     iGrayscale = NULL;
       
   351     }
       
   352 
       
   353 // -----------------------------------------------------------------------------
       
   354 // CAknsRlEffectPluginBumpMap::SetParametersL
       
   355 // -----------------------------------------------------------------------------
       
   356 //
       
   357 void CAknsRlEffectPluginBumpMap::SetParametersL( MAknsRlParameterIterator& aParameters )
       
   358     {
       
   359     while( aParameters.HasNext() )
       
   360         {
       
   361         const TAknsRlParameterData* param = aParameters.NextL();
       
   362 
       
   363         // Fetch azimuth value
       
   364         if( param->iName->Compare( KAknsRlEffectBumpMapAzimuth ) == 0 )
       
   365             {
       
   366             if( param->iType != EAknsRlParameterTypeNumber )
       
   367                 User::Leave( KErrArgument );
       
   368 
       
   369             if( param->iNumber < 0 || param->iNumber > 360 )
       
   370                 User::Leave( KErrArgument );
       
   371 
       
   372             // Convert from degrees to radians: [0, 360] -> [0, 2 * KPi]
       
   373             iAzimuth = (TReal( param->iNumber ) / 360.0) * 2 * KPi;
       
   374             }
       
   375         // Fetch elevation value
       
   376         else if( param->iName->Compare( KAknsRlEffectBumpMapElevation ) == 0 )
       
   377             {
       
   378             if( param->iType != EAknsRlParameterTypeNumber )
       
   379                 User::Leave( KErrArgument );
       
   380 
       
   381             if( param->iNumber < 0 || param->iNumber > 180 )
       
   382                 User::Leave( KErrArgument );
       
   383 
       
   384             // Convert from degrees to radians: [0, 180] -> [0, KPi]
       
   385             iElevation = (TReal( param->iNumber ) / 180.0) * KPi;
       
   386             }
       
   387         // Fetch depth value
       
   388         else if( param->iName->Compare( KAknsRlEffectBumpMapDepth ) == 0 )
       
   389             {
       
   390             if( param->iType != EAknsRlParameterTypeNumber )
       
   391                 User::Leave( KErrArgument );
       
   392 
       
   393             if( param->iNumber <= 0 )
       
   394                 User::Leave( KErrArgument );
       
   395 
       
   396             iDepth = param->iNumber;
       
   397             }
       
   398         // Fetch blend mode value
       
   399         else if( param->iName->Compare( KAknsRlEffectBumpMapBlendMode ) == 0 )
       
   400             {
       
   401             if( param->iType != EAknsRlParameterTypeNumber )
       
   402                 User::Leave( KErrArgument );
       
   403 
       
   404             if( param->iNumber < EAknsRlChannelBlendNormal ||
       
   405                 param->iNumber > EAknsRlChannelBlendBurn )
       
   406                 User::Leave( KErrArgument );
       
   407 
       
   408             iBlendMode = param->iNumber;
       
   409             }
       
   410         // Fetch blend factor value
       
   411         else if( param->iName->Compare( KAknsRlEffectBumpMapBlendFactor ) == 0 )
       
   412             {
       
   413             if( param->iType != EAknsRlParameterTypeNumber )
       
   414                 User::Leave( KErrArgument );
       
   415 
       
   416             iBlendFactor = param->iNumber;
       
   417             }
       
   418         }
       
   419     }
       
   420 
       
   421 // -----------------------------------------------------------------------------
       
   422 // CAknsRlEffectPluginBumpMap::GetCapabilities
       
   423 // -----------------------------------------------------------------------------
       
   424 //
       
   425 void CAknsRlEffectPluginBumpMap::GetCapabilities( TAknsRlEffectCaps& aCaps )
       
   426     {
       
   427     aCaps.iOutputLayerSupport = KAknsRlLayerRGBOnly;
       
   428     aCaps.iInputLayerASupport = KAknsRlLayerRGBOnly;
       
   429     aCaps.iInputLayerBSupport = KAknsRlLayerNone;
       
   430     }
       
   431 
       
   432 // -----------------------------------------------------------------------------
       
   433 // CAknsRlEffectPluginBumpMap::Render
       
   434 // -----------------------------------------------------------------------------
       
   435 //
       
   436 TInt CAknsRlEffectPluginBumpMap::Render( const TAknsRlRenderOpParam& aParam )
       
   437     {
       
   438     if( !iContext ) // We absolutely need the context
       
   439         {
       
   440         return KErrBadHandle;
       
   441         }
       
   442 
       
   443     // To do anything we need both, the output layer and input layer
       
   444     if( ( aParam.iOutputLayerStatus & KAknsRlLayerRGBOnly ) &&
       
   445         ( aParam.iInputLayerAStatus & KAknsRlLayerRGBOnly ) )
       
   446         {
       
   447         // Query the layers, uninitialized because we process the whole image
       
   448         TAknsRlLayerData dataTarget;
       
   449         TRAPD( err, iContext->GetLayerDataL( dataTarget, aParam.iOutputLayerIndex,
       
   450                                              aParam.iOutputLayerStatus, EFalse ) );
       
   451         if( KErrNone != err )
       
   452             return KErrArgument;
       
   453 
       
   454         TAknsRlLayerData dataSource;
       
   455         TRAP( err, iContext->GetLayerDataL( dataSource, aParam.iInputLayerAIndex,
       
   456                                             aParam.iInputLayerAStatus, EFalse ) );
       
   457         if( KErrNone != err )
       
   458             return KErrArgument;
       
   459 
       
   460         if( !dataTarget.iRGBBitmap ) // We need the target bitmap
       
   461             return KErrBadHandle;
       
   462 
       
   463         if( !dataSource.iRGBBitmap ) // We need the source bitmap
       
   464             return KErrBadHandle;
       
   465 
       
   466         TDisplayMode modeT = dataTarget.iRGBBitmap->DisplayMode();
       
   467         TDisplayMode modeS = dataSource.iRGBBitmap->DisplayMode();
       
   468 
       
   469         // Rgb -> Rgb modes
       
   470         if( EColor64K == modeS && EColor64K == modeT )
       
   471             {
       
   472             return AknsRlEffectBumpMap<TUint16,0,5,6,5>::Process(
       
   473                             *dataTarget.iRGBBitmap,
       
   474                             *dataSource.iRGBBitmap,
       
   475                             iAzimuth,
       
   476                             iElevation,
       
   477                             iDepth,
       
   478                             TAknsRlChannelBlendMode( iBlendMode ),
       
   479                             iBlendFactor,
       
   480                             iGrayscale );
       
   481             }
       
   482         else if( EColor16MU == modeS && EColor16MU == modeT )
       
   483             {
       
   484             return AknsRlEffectBumpMap<TUint32,8,8,8,8>::Process(
       
   485                             *dataTarget.iRGBBitmap,
       
   486                             *dataSource.iRGBBitmap,
       
   487                             iAzimuth,
       
   488                             iElevation,
       
   489                             iDepth,
       
   490                             TAknsRlChannelBlendMode( iBlendMode ),
       
   491                             iBlendFactor,
       
   492                             iGrayscale );
       
   493             }
       
   494         else
       
   495             {
       
   496             // Provided layers have illegal display mode combination
       
   497             return KErrArgument;
       
   498             }
       
   499         }
       
   500 
       
   501     // The else part, required layers were not provided
       
   502     return KErrArgument;
       
   503     }
       
   504 
       
   505 // End of File