--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/skins/AknSkins/rlpluginsrc/AknsRlEffectPluginBumpMap.cpp Thu Dec 17 09:14:12 2009 +0200
@@ -0,0 +1,505 @@
+/*
+* Copyright (c) 2004-2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Bump-mapping for effects.
+*
+*/
+
+
+// INCLUDE FILES
+#include <e32math.h>
+
+#include "AknsRlEffectPluginBumpMap.h"
+#include "AknsRlEffectUtil.h"
+
+// CONSTANTS
+const TReal KPixelScale = 255.9;
+
+// ====================== TEMPLATED IMPL. OF BUMPMAP ===========================
+/**
+* Template implementation of BumpMap. Type defines the used data type for
+* iterating over the bitmap data. X, R, G and B define the used pixel color bit
+* layout.
+*/
+template<class Type,TInt X, TInt R, TInt G, TInt B>
+class AknsRlEffectBumpMap
+ {
+ public:
+ /**
+ * @return KErrNone if processing was ok, something else on error.
+ */
+ static TInt Process( const CFbsBitmap& aTarget,
+ const CFbsBitmap& aSource,
+ const TReal aAzimuth,
+ const TReal aElevation,
+ const TInt aDepth,
+ TAknsRlChannelBlendMode aBlendMode,
+ const TInt aBlendFactor,
+ TUint8* aGrayscale )
+ {
+ // CFbsBitmap::ScanLineLength returns bytes, determine the scanw when using Type
+ TInt scanW = CFbsBitmap::ScanLineLength( aTarget.SizeInPixels().iWidth,
+ aTarget.DisplayMode() ) / sizeof(Type);
+ TInt width = aTarget.SizeInPixels().iWidth;
+ TInt height = aTarget.SizeInPixels().iHeight;
+
+ TInt grayW = width + 2;
+ TInt grayH = height + 2;
+
+ TInt x, y;
+
+ // Step 1: Grayscale the image
+ TInt pitch = scanW - width;
+ // The grayscale buffer has that one pixel extra border
+ TUint8* buf = aGrayscale + grayW + 1;
+ aSource.LockHeap(); // Lock the global bitmap heap
+ Type* dataS = reinterpret_cast<Type*>( aSource.DataAddress() );
+
+ for( y=0; y < height; y++ )
+ {
+ for( x=0; x < width; x++ )
+ {
+ *buf = AknsRlUtil::Grayscale( AknsRlRgb<Type,X,R,G,B>::R8(*dataS),
+ AknsRlRgb<Type,X,R,G,B>::G8(*dataS),
+ AknsRlRgb<Type,X,R,G,B>::B8(*dataS) );
+ buf++;
+ dataS++;
+ }
+
+ // Skip possibly trailing pixels on aSource
+ dataS = dataS + pitch;
+ buf = buf + 2;
+ }
+
+ aSource.UnlockHeap(); // Unlock the global bitmap heap
+
+ // Next, fill the grayscale 1 pixel border by copying the neighbouring
+ // pixel values
+
+ // Top row
+ buf = aGrayscale + 1;
+ for( x=1; x < grayW - 2; x++ )
+ {
+ *buf = *( buf + grayW );
+ buf++;
+ }
+
+ // Bottom row
+ buf = aGrayscale + grayW * (grayH - 1) + 1;
+ for( x=1; x < grayW - 2; x++ )
+ {
+ *buf = *( buf - grayW );
+ buf++;
+ }
+
+ // Left column
+ buf = aGrayscale + grayW;
+ for( y=1; y < grayH - 2; y++ )
+ {
+ *buf = *( buf + 1 );
+ buf = buf + grayW;
+ }
+
+ // Right column
+ buf = aGrayscale + 2 * grayW - 1;
+ for( y=1; y < grayH - 2; y++ )
+ {
+ *buf = *( buf - 1 );
+ buf = buf + grayW;
+ }
+
+ // Top left corner
+ aGrayscale[ 0 ] = aGrayscale[ grayW + 1 ];
+ // Top right corner
+ aGrayscale[ grayW - 1 ] = aGrayscale[ 2 * grayW - 2 ];
+ // Bottom left corner
+ aGrayscale[ (grayH - 1) * grayW ] = aGrayscale[ ((grayH - 2 ) * grayW) + 1];
+ // Bottom right corner
+ aGrayscale[ (grayH * grayW) - 1 ] = aGrayscale[ (grayH - 2) * grayW + grayW - 2 ];
+
+ // Step 2: Create the bump map by embossing. The embossing routine
+ // follows the ANSI C code from the article "Fast Embossing Effects on
+ // Raster Image Data" by John Schlag, jfs@kerner.com, in "Graphics Gems
+ // IV", Academic Press, 1994
+
+ // Determine the light direction vector
+ TReal aziRes, eleRes;
+ TInt err;
+
+ err = Math::Cos(aziRes, aAzimuth);
+ if( KErrNone != err )
+ return err;
+
+ err = Math::Cos(eleRes, aElevation);
+ if( KErrNone != err )
+ return err;
+
+ TInt lx = TInt( aziRes * eleRes * KPixelScale );
+
+ err = Math::Sin(aziRes, aAzimuth);
+ if( KErrNone != err )
+ return err;
+
+ TInt ly = TInt( aziRes * eleRes * KPixelScale );
+
+ err = Math::Sin(eleRes, aElevation);
+ if( KErrNone != err )
+ return err;
+
+ TInt lz = TInt( eleRes * KPixelScale );
+
+ // Determine a constant z of image surface normal
+ TInt nz = (6 * 255) / aDepth; // Depth always > 0
+ TInt nz2 = nz * nz;
+ TInt nzlz = nz * lz;
+ TInt nx, ny;
+ TInt NdotL;
+ TInt shade, root;
+ TInt r, g, b;
+ TReal sqrt;
+
+ aTarget.LockHeap( ETrue ); // Lock the global bitmap heap
+ dataS = reinterpret_cast<Type*>( aSource.DataAddress() );
+ Type* dataT = reinterpret_cast<Type*>( aTarget.DataAddress() );
+
+ // The grayscale buffer has that one pixel extra border
+ buf = aGrayscale + grayW + 1;
+
+ // We can process the whole source image directly because the
+ // grayscale image has 1 pixel extra border (convolution can refer
+ // outside the source image dimensions).
+ for(y=0; y < height; y++)
+ {
+ for(x=0; x < width; x++)
+ {
+ // Do embossing
+ nx = *(buf - grayW - 1) + *(buf - 1) + *(buf + grayW - 1) -
+ *(buf - grayW + 1) - *(buf + 1) - *(buf + grayW + 1);
+ ny = *(buf + grayW - 1) + *(buf + grayW) + *(buf + grayW + 1) -
+ *(buf - grayW - 1) - *(buf - grayW) - *(buf - grayW + 1);
+
+ if( nx == 0 && ny == 0 )
+ shade = lz;
+ else if( (NdotL = nx*lx + ny*ly + nzlz) < 0 )
+ shade = 0;
+ else
+ {
+ // Note that the error value is ignored because
+ // nx*nx + ny*ny + nz2 >= 0 always.
+ Math::Sqrt( sqrt, nx*nx + ny*ny + nz2 );
+ root = TInt( sqrt );
+ if( root )
+ shade = NdotL / root;
+ else // Square root was rounded to zero
+ {
+ // ( nx * nx + ny * ny ) is always >= 0. If aDepth is
+ // large enough nz2 will be small enough so that sqrt(
+ // nx*nx + ny*ny + nz2 ) returns < 1.0 and the result
+ // rounds to zero.
+ shade = 255;
+ }
+ }
+
+ if(shade < 0)
+ shade = 0;
+ else if(shade > 255)
+ shade = 255;
+
+ // Step 3: Do Channel blending
+ r = AknsRlChannelBlend::Blend( aBlendMode,
+ aBlendFactor,
+ AknsRlRgb<Type,X,R,G,B>::R8(*dataS),
+ TUint8( shade ));
+ g = AknsRlChannelBlend::Blend( aBlendMode,
+ aBlendFactor,
+ AknsRlRgb<Type,X,R,G,B>::G8(*dataS),
+ TUint8( shade ));
+ b = AknsRlChannelBlend::Blend( aBlendMode,
+ aBlendFactor,
+ AknsRlRgb<Type,X,R,G,B>::B8(*dataS),
+ TUint8( shade ));
+
+ AknsRlRgb<Type,X,R,G,B>::SetRgb8(dataT, TUint8(r), TUint8(g), TUint8(b));
+
+ buf++;
+ dataS++;
+ dataT++;
+ }
+
+ buf = buf + 2;
+ dataS = dataS + pitch;
+ dataT = dataT + pitch;
+ }
+
+ aTarget.UnlockHeap( ETrue );
+
+ return KErrNone;
+ }
+ };
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginBumpMap::CAknsRlEffectPluginBumpMap
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CAknsRlEffectPluginBumpMap::CAknsRlEffectPluginBumpMap()
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CAknsRlEffectPluginBumpMap::~CAknsRlEffectPluginBumpMap()
+ {
+ // The user of this plugin should call deactivate eventually...but we
+ // delete grayscale buffer here too (just in case)
+ delete [] iGrayscale;
+ iContext = NULL;
+ }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginBumpMap::EffectUid
+// -----------------------------------------------------------------------------
+//
+TUid CAknsRlEffectPluginBumpMap::EffectUid() const
+ {
+ return TUid::Uid( KAknsRlEffectPluginBumpMapUID );
+ }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginBumpMap::Effect
+// -----------------------------------------------------------------------------
+//
+MAknsRlEffect* CAknsRlEffectPluginBumpMap::Effect( const TInt aInterface )
+ {
+ if( aInterface == KAknsRlEffectPluginInterfaceEffect )
+ return this;
+ return NULL;
+ }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginBumpMap::InitializeL
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginBumpMap::InitializeL()
+ {
+ iContext = NULL;
+ }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginBumpMap::Release
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginBumpMap::Release()
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginBumpMap::ActivateL
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginBumpMap::ActivateL( MAknsRlEffectContext* aContext )
+ {
+ if( !aContext ) // We absolutely need the context
+ {
+ User::Leave( KErrArgument );
+ }
+
+ iContext = aContext;
+
+ iAzimuth = 0.0;
+ iElevation = 0.59; // ~34 in degrees
+ iDepth = 10;
+ iBlendMode = EAknsRlChannelBlendNormal;
+ iBlendFactor = 255;
+
+ // Because the grayscale image is convoluted we need to create grayscale
+ // image that has extra one pixel border.
+ TSize size = aContext->LayerSize();
+ size.iWidth = size.iWidth + 2;
+ size.iHeight = size.iHeight + 2;
+
+ // Calling activate multiple times in row in unlikely but we delete the
+ // grayscale buffer just in case.
+ delete [] iGrayscale;
+ iGrayscale = NULL;
+ iGrayscale = new(ELeave) TUint8[ size.iWidth * size.iHeight ]; //lint !e119 Enough arguments
+ }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginBumpMap::Deactivate
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginBumpMap::Deactivate()
+ {
+ delete [] iGrayscale;
+ iGrayscale = NULL;
+ }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginBumpMap::SetParametersL
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginBumpMap::SetParametersL( MAknsRlParameterIterator& aParameters )
+ {
+ while( aParameters.HasNext() )
+ {
+ const TAknsRlParameterData* param = aParameters.NextL();
+
+ // Fetch azimuth value
+ if( param->iName->Compare( KAknsRlEffectBumpMapAzimuth ) == 0 )
+ {
+ if( param->iType != EAknsRlParameterTypeNumber )
+ User::Leave( KErrArgument );
+
+ if( param->iNumber < 0 || param->iNumber > 360 )
+ User::Leave( KErrArgument );
+
+ // Convert from degrees to radians: [0, 360] -> [0, 2 * KPi]
+ iAzimuth = (TReal( param->iNumber ) / 360.0) * 2 * KPi;
+ }
+ // Fetch elevation value
+ else if( param->iName->Compare( KAknsRlEffectBumpMapElevation ) == 0 )
+ {
+ if( param->iType != EAknsRlParameterTypeNumber )
+ User::Leave( KErrArgument );
+
+ if( param->iNumber < 0 || param->iNumber > 180 )
+ User::Leave( KErrArgument );
+
+ // Convert from degrees to radians: [0, 180] -> [0, KPi]
+ iElevation = (TReal( param->iNumber ) / 180.0) * KPi;
+ }
+ // Fetch depth value
+ else if( param->iName->Compare( KAknsRlEffectBumpMapDepth ) == 0 )
+ {
+ if( param->iType != EAknsRlParameterTypeNumber )
+ User::Leave( KErrArgument );
+
+ if( param->iNumber <= 0 )
+ User::Leave( KErrArgument );
+
+ iDepth = param->iNumber;
+ }
+ // Fetch blend mode value
+ else if( param->iName->Compare( KAknsRlEffectBumpMapBlendMode ) == 0 )
+ {
+ if( param->iType != EAknsRlParameterTypeNumber )
+ User::Leave( KErrArgument );
+
+ if( param->iNumber < EAknsRlChannelBlendNormal ||
+ param->iNumber > EAknsRlChannelBlendBurn )
+ User::Leave( KErrArgument );
+
+ iBlendMode = param->iNumber;
+ }
+ // Fetch blend factor value
+ else if( param->iName->Compare( KAknsRlEffectBumpMapBlendFactor ) == 0 )
+ {
+ if( param->iType != EAknsRlParameterTypeNumber )
+ User::Leave( KErrArgument );
+
+ iBlendFactor = param->iNumber;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginBumpMap::GetCapabilities
+// -----------------------------------------------------------------------------
+//
+void CAknsRlEffectPluginBumpMap::GetCapabilities( TAknsRlEffectCaps& aCaps )
+ {
+ aCaps.iOutputLayerSupport = KAknsRlLayerRGBOnly;
+ aCaps.iInputLayerASupport = KAknsRlLayerRGBOnly;
+ aCaps.iInputLayerBSupport = KAknsRlLayerNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CAknsRlEffectPluginBumpMap::Render
+// -----------------------------------------------------------------------------
+//
+TInt CAknsRlEffectPluginBumpMap::Render( const TAknsRlRenderOpParam& aParam )
+ {
+ if( !iContext ) // We absolutely need the context
+ {
+ return KErrBadHandle;
+ }
+
+ // To do anything we need both, the output layer and input layer
+ if( ( aParam.iOutputLayerStatus & KAknsRlLayerRGBOnly ) &&
+ ( aParam.iInputLayerAStatus & KAknsRlLayerRGBOnly ) )
+ {
+ // Query the layers, uninitialized because we process the whole image
+ TAknsRlLayerData dataTarget;
+ TRAPD( err, iContext->GetLayerDataL( dataTarget, aParam.iOutputLayerIndex,
+ aParam.iOutputLayerStatus, EFalse ) );
+ if( KErrNone != err )
+ return KErrArgument;
+
+ TAknsRlLayerData dataSource;
+ TRAP( err, iContext->GetLayerDataL( dataSource, aParam.iInputLayerAIndex,
+ aParam.iInputLayerAStatus, EFalse ) );
+ if( KErrNone != err )
+ return KErrArgument;
+
+ if( !dataTarget.iRGBBitmap ) // We need the target bitmap
+ return KErrBadHandle;
+
+ if( !dataSource.iRGBBitmap ) // We need the source bitmap
+ return KErrBadHandle;
+
+ TDisplayMode modeT = dataTarget.iRGBBitmap->DisplayMode();
+ TDisplayMode modeS = dataSource.iRGBBitmap->DisplayMode();
+
+ // Rgb -> Rgb modes
+ if( EColor64K == modeS && EColor64K == modeT )
+ {
+ return AknsRlEffectBumpMap<TUint16,0,5,6,5>::Process(
+ *dataTarget.iRGBBitmap,
+ *dataSource.iRGBBitmap,
+ iAzimuth,
+ iElevation,
+ iDepth,
+ TAknsRlChannelBlendMode( iBlendMode ),
+ iBlendFactor,
+ iGrayscale );
+ }
+ else if( EColor16MU == modeS && EColor16MU == modeT )
+ {
+ return AknsRlEffectBumpMap<TUint32,8,8,8,8>::Process(
+ *dataTarget.iRGBBitmap,
+ *dataSource.iRGBBitmap,
+ iAzimuth,
+ iElevation,
+ iDepth,
+ TAknsRlChannelBlendMode( iBlendMode ),
+ iBlendFactor,
+ iGrayscale );
+ }
+ else
+ {
+ // Provided layers have illegal display mode combination
+ return KErrArgument;
+ }
+ }
+
+ // The else part, required layers were not provided
+ return KErrArgument;
+ }
+
+// End of File