位图
在Symbian操作系统中使用位图的首选方法是创建MBM(Multi-Bitmap file)文件,在程序运行时从MBM文件中获取位图。一个MBM文件包含多个给定的位图。MBM或者是文件存储体或者是ROM图片类型。ROM图片 MBM不是压缩的,因此访问MBM不消耗RAM。文件存储体MBM是被压缩的(默认),由于解压访问文件存储体MBM消耗内存。MBM文件的默认的类型是 文件存储体类型。
MBM通过使用位图转换工具,bmconv,以Windows位图创建。Bmconv可以直接从命令行来使用,也可以在工程文件(mmp)中定义位图,当编译工程时,在目标路径下生成MBM文件:
// MyGame.mmp
START BITMAP MyGame.mbm
HEADER
TARGETPATH ..\..\..\..\wins\c\system\apps\MyGame
SOURCEPATH ..\MyBitmaps
// color-depth source-bitmap
SOURCE c12 image1.bmp
SOURCE c12 image2.bmp
SOURCE c12 image3.bmp
END
每一个位图都基于mmp中定义的位图的header赋予一个枚举ID号 。这些ID生成到系统的include路径(epoc32\include)下的mbg文件中。Mbm文件中的位图能够通过这个ID号来访问。每一个ID 号自动生成如下格式:EMbm<MBM文件名><位图文件名>,例如,EMbmMygameImage1。
MBM文件中的位图可以用如下的代码来访问:
#include <MyGame.mbg> // generated on compilation
#include <aknutils.h> // for CompleteWithAppPath()
CFbsBitmap* CMyGameView::LoadMyBitmapL()
{
// set the name of the multi-bitmap file containing the bitmaps
_LIT(KMBMFileName,"MyGame.mbm";);
TFileName mbmFileName(KMBMFileName);
CompleteWithAppPath(mbmFileName);
// load the bitmap from the mbm file
CFbsBitmap* bitmap = new (ELeave) CFbsBitmap();
CleanupStack::PushL(bitmap);
// EMbmMygameImage1 is enumerated value from MyGame.mbg file
User::LeaveIfError(bitmap->Load(mbmFileName, EMbmMygameImage1));
CleanupStack::Pop(); // bitmap
return bitmap;
}
位图被装载后,可以用如BitBlt显屏:
void CMyGameView::Draw( const TRect& /*aRect*/ ) const
{
// Get the system graphics context
CWindowGc& gc = SystemGc();
// Draw the bitmap
gc.BitBlt( TPoint(10, 10), iMyShipBitmap);
}
部分透明的位图可以使用蒙板。蒙板是黑白位图(1位位图节省空间),白色代表透明区域,只有黑色像素部分从原位图中显屏。大多数Draw方法也允许反转蒙板,黑色透明。蒙板和其它位图一样装载,一个带有蒙板的位图显屏可以通过例如,BitBltMasked:
void CMyGameView::Draw( const TRect& /*aRect*/ ) const
{
// Get the system graphics context
CWindowGc& gc = SystemGc();
// Draw masked bitmap
gc.BitBltMasked( TPoint(10, 10), iMyShipBitmap, iMyShipRect,
iMyShipMask, EFalse);
}
当一个非矩形,不规则形状的位图对象(sprite)后面的背景图片应该可见时,蒙板位图尤其有用。
当程序在一个窗口显屏位图时,位图被转换成同样的显示模式--或者说是色彩深度(在Symbian操作系统中,显示模式通常指色彩深度而不是分辨率)-- 同窗口一样的显示模式。这是一个消耗时间的操作,这实际上会使显屏变慢。因此,在装载位图时应该转变成正确的色彩深度,适宜在游戏初始化或者是游戏的某一 级时。在实际应用中通常会给所有的位图创建一个container类用来在游戏中处理装载,转换和存储位图。
转换能够用一个临时位图来实现,如下所示:
CFbsBitmap* CMyGameView::LoadAndConvertBitmapL(
Const TDesC& aFileName, TInt aBitmapId )
{
// Load the original bitmap
CFbsBitmap* originalBitmap = new ( ELeave ) CFbsBitmap();
CleanupStack::PushL( originalBitmap );
User::LeaveIfError( originalBitmap->Load( aFileName, aBitmapId,
EFalse ) );
// Create a new bitmap, graphics device and context
CFbsBitmap* newBitmap = new ( ELeave ) CFbsBitmap();
CleanupStack::PushL( newBitmap );
newBitmap->Create( originalBitmap->SizeInPixels(),
Window()->DisplayMode() );
CFbsBitmapDevice* graphicsDevice = CFbsBitmapDevice::NewL(
bitmapConverted );
CleanupStack::PushL( graphicsDevice );
CFbsBitGc* graphicsContext;
User::LeaveIfError( graphicsDevice->CreateContext(
graphicsContext ) );
// Blit the loaded bitmap to the new bitmap (the actual
// conversion)
bitmapContext->BitBlt( TPoint(0,0), originalBitmap );
CleanupStack::Pop(3);
delete bitmapContext;
delete bitmapDevice;
delete originalBitmap;
return newBitmap;
}
该方法通过参数获取一个文件名和一个位图ID,从MBM文件装载了相应的位图。转换位图到窗口显示模式,新的位图文件被创建,装载的位图文件被复制到其中。
位图在运行时能够旋转和按比例变换大小。在实际中运用一个位图的大小变换和旋转比运用具有不同大小和方向多个位图更常见(例如,一个360度旋转的船的sprite):
CMdaBitmapRotator;按照给定的角度旋转。
CMdaBitmapScaler;变换位图大小。
S60开发平台2.0以前不赞成用上面提到的方法,开发者应该用下面的方法:
CbitmapRotator
CbitmapScaler
这两个方法本身是异步的,需要一个继承MMdaImageUtilObserver 的observer类,用来通知操作完成。
如果提供的位图操作方法不够用,也可以用图形API提供的显屏方法(见前面的为位图创建graphics context的LoadAndConvertBitmapL方法)修改装载的位图。如果速度是一个关键的因素,你也可以用指针直接访问位图数据按需修改。
可以使用CFbsBitmap::DataAddress方法直接访问位图数据,这个方法返回位图数据区的开始位置(位图的左上角)。在获取数据地址和修 改数据前应该注意一点,由于内存碎片整理,位图的数据地址可能会在运行时改变。这就意味着堆栈中的位图数据区在用TBitmapUtil,或者S60开发 平台2.0,CFbsBitmap的LockHeap和UnlockHeap方法访问之前必须被锁定。
当直接访问位图数据时,必须注意数据的格式,例如,16位位图每个象素是5-6-5格式(红-绿-蓝),12位位图是4-4-4格式(字节的低12位)。
下面的代码示范了一个简单的效果,增加给定16位位图的每个像素的红色成分:
void CMyGameView::DoMyBitmapEffect(CFbsBitmap* aBitmap)
{
// Lock heap
// For series 60 2.0 use:
// aBitmap->LockHeap();
// For series 60 1.0 use:
TBitmapUtil bitmapUtil(aBitmap);
bitmapUtil.Begin( TPoint(0,0) );
// Edit bitmap
TSize bitmapSize = aBitmap->SizeInPixels();
// NOTE: TUint16* applies to 16bit bitmaps only; the pointer must
// correspond the bit depth of the bitmap.
TUint16* bitmapData = (TUint16*)aBitmap->DataAddress();
for ( TInt y = 0; y < bitmapSize.iHeight; y++ );
{
for ( TInt x = 0; x < bitmapSize.iWidth; x++ )
{
// Increase colour value of each pixel by one
*bitmapData = ( *bitmapData & 31 ) | // blue
( ( *bitmapData >> 5 ) & 63 ) | // green
( ( *bitmapData >> 11 ) & 31 + 1 ); // red
bitmapData++;
}
}
// Unlock heap
// For series 60 1.0 use:
bitmapUtil.End();
// For series 60 2.0 use:
// aBitmap->UnlockHeap();
}
S60开发平台2.0以前,2D硬件加速API有很多的位图操作方法,像transparent blits,只是通过定义透明颜色不用蒙板就能实现透明处理。(见Hardware Acceleration)。
在Symbian操作系统中使用位图的首选方法是创建MBM(Multi-Bitmap file)文件,在程序运行时从MBM文件中获取位图。一个MBM文件包含多个给定的位图。MBM或者是文件存储体或者是ROM图片类型。ROM图片 MBM不是压缩的,因此访问MBM不消耗RAM。文件存储体MBM是被压缩的(默认),由于解压访问文件存储体MBM消耗内存。MBM文件的默认的类型是 文件存储体类型。
MBM通过使用位图转换工具,bmconv,以Windows位图创建。Bmconv可以直接从命令行来使用,也可以在工程文件(mmp)中定义位图,当编译工程时,在目标路径下生成MBM文件:
// MyGame.mmp
START BITMAP MyGame.mbm
HEADER
TARGETPATH ..\..\..\..\wins\c\system\apps\MyGame
SOURCEPATH ..\MyBitmaps
// color-depth source-bitmap
SOURCE c12 image1.bmp
SOURCE c12 image2.bmp
SOURCE c12 image3.bmp
END
每一个位图都基于mmp中定义的位图的header赋予一个枚举ID号 。这些ID生成到系统的include路径(epoc32\include)下的mbg文件中。Mbm文件中的位图能够通过这个ID号来访问。每一个ID 号自动生成如下格式:EMbm<MBM文件名><位图文件名>,例如,EMbmMygameImage1。
MBM文件中的位图可以用如下的代码来访问:
#include <MyGame.mbg> // generated on compilation
#include <aknutils.h> // for CompleteWithAppPath()
CFbsBitmap* CMyGameView::LoadMyBitmapL()
{
// set the name of the multi-bitmap file containing the bitmaps
_LIT(KMBMFileName,"MyGame.mbm";);
TFileName mbmFileName(KMBMFileName);
CompleteWithAppPath(mbmFileName);
// load the bitmap from the mbm file
CFbsBitmap* bitmap = new (ELeave) CFbsBitmap();
CleanupStack::PushL(bitmap);
// EMbmMygameImage1 is enumerated value from MyGame.mbg file
User::LeaveIfError(bitmap->Load(mbmFileName, EMbmMygameImage1));
CleanupStack::Pop(); // bitmap
return bitmap;
}
位图被装载后,可以用如BitBlt显屏:
void CMyGameView::Draw( const TRect& /*aRect*/ ) const
{
// Get the system graphics context
CWindowGc& gc = SystemGc();
// Draw the bitmap
gc.BitBlt( TPoint(10, 10), iMyShipBitmap);
}
部分透明的位图可以使用蒙板。蒙板是黑白位图(1位位图节省空间),白色代表透明区域,只有黑色像素部分从原位图中显屏。大多数Draw方法也允许反转蒙板,黑色透明。蒙板和其它位图一样装载,一个带有蒙板的位图显屏可以通过例如,BitBltMasked:
void CMyGameView::Draw( const TRect& /*aRect*/ ) const
{
// Get the system graphics context
CWindowGc& gc = SystemGc();
// Draw masked bitmap
gc.BitBltMasked( TPoint(10, 10), iMyShipBitmap, iMyShipRect,
iMyShipMask, EFalse);
}
当一个非矩形,不规则形状的位图对象(sprite)后面的背景图片应该可见时,蒙板位图尤其有用。
当程序在一个窗口显屏位图时,位图被转换成同样的显示模式--或者说是色彩深度(在Symbian操作系统中,显示模式通常指色彩深度而不是分辨率)-- 同窗口一样的显示模式。这是一个消耗时间的操作,这实际上会使显屏变慢。因此,在装载位图时应该转变成正确的色彩深度,适宜在游戏初始化或者是游戏的某一 级时。在实际应用中通常会给所有的位图创建一个container类用来在游戏中处理装载,转换和存储位图。
转换能够用一个临时位图来实现,如下所示:
CFbsBitmap* CMyGameView::LoadAndConvertBitmapL(
Const TDesC& aFileName, TInt aBitmapId )
{
// Load the original bitmap
CFbsBitmap* originalBitmap = new ( ELeave ) CFbsBitmap();
CleanupStack::PushL( originalBitmap );
User::LeaveIfError( originalBitmap->Load( aFileName, aBitmapId,
EFalse ) );
// Create a new bitmap, graphics device and context
CFbsBitmap* newBitmap = new ( ELeave ) CFbsBitmap();
CleanupStack::PushL( newBitmap );
newBitmap->Create( originalBitmap->SizeInPixels(),
Window()->DisplayMode() );
CFbsBitmapDevice* graphicsDevice = CFbsBitmapDevice::NewL(
bitmapConverted );
CleanupStack::PushL( graphicsDevice );
CFbsBitGc* graphicsContext;
User::LeaveIfError( graphicsDevice->CreateContext(
graphicsContext ) );
// Blit the loaded bitmap to the new bitmap (the actual
// conversion)
bitmapContext->BitBlt( TPoint(0,0), originalBitmap );
CleanupStack::Pop(3);
delete bitmapContext;
delete bitmapDevice;
delete originalBitmap;
return newBitmap;
}
该方法通过参数获取一个文件名和一个位图ID,从MBM文件装载了相应的位图。转换位图到窗口显示模式,新的位图文件被创建,装载的位图文件被复制到其中。
位图在运行时能够旋转和按比例变换大小。在实际中运用一个位图的大小变换和旋转比运用具有不同大小和方向多个位图更常见(例如,一个360度旋转的船的sprite):
CMdaBitmapRotator;按照给定的角度旋转。
CMdaBitmapScaler;变换位图大小。
S60开发平台2.0以前不赞成用上面提到的方法,开发者应该用下面的方法:
CbitmapRotator
CbitmapScaler
这两个方法本身是异步的,需要一个继承MMdaImageUtilObserver 的observer类,用来通知操作完成。
如果提供的位图操作方法不够用,也可以用图形API提供的显屏方法(见前面的为位图创建graphics context的LoadAndConvertBitmapL方法)修改装载的位图。如果速度是一个关键的因素,你也可以用指针直接访问位图数据按需修改。
可以使用CFbsBitmap::DataAddress方法直接访问位图数据,这个方法返回位图数据区的开始位置(位图的左上角)。在获取数据地址和修 改数据前应该注意一点,由于内存碎片整理,位图的数据地址可能会在运行时改变。这就意味着堆栈中的位图数据区在用TBitmapUtil,或者S60开发 平台2.0,CFbsBitmap的LockHeap和UnlockHeap方法访问之前必须被锁定。
当直接访问位图数据时,必须注意数据的格式,例如,16位位图每个象素是5-6-5格式(红-绿-蓝),12位位图是4-4-4格式(字节的低12位)。
下面的代码示范了一个简单的效果,增加给定16位位图的每个像素的红色成分:
void CMyGameView::DoMyBitmapEffect(CFbsBitmap* aBitmap)
{
// Lock heap
// For series 60 2.0 use:
// aBitmap->LockHeap();
// For series 60 1.0 use:
TBitmapUtil bitmapUtil(aBitmap);
bitmapUtil.Begin( TPoint(0,0) );
// Edit bitmap
TSize bitmapSize = aBitmap->SizeInPixels();
// NOTE: TUint16* applies to 16bit bitmaps only; the pointer must
// correspond the bit depth of the bitmap.
TUint16* bitmapData = (TUint16*)aBitmap->DataAddress();
for ( TInt y = 0; y < bitmapSize.iHeight; y++ );
{
for ( TInt x = 0; x < bitmapSize.iWidth; x++ )
{
// Increase colour value of each pixel by one
*bitmapData = ( *bitmapData & 31 ) | // blue
( ( *bitmapData >> 5 ) & 63 ) | // green
( ( *bitmapData >> 11 ) & 31 + 1 ); // red
bitmapData++;
}
}
// Unlock heap
// For series 60 1.0 use:
bitmapUtil.End();
// For series 60 2.0 use:
// aBitmap->UnlockHeap();
}
S60开发平台2.0以前,2D硬件加速API有很多的位图操作方法,像transparent blits,只是通过定义透明颜色不用蒙板就能实现透明处理。(见Hardware Acceleration)。
浙公网安备 33010602011771号