<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog336280.html" frameborder="0" width="336" scrolling="no" height="280"></iframe>
参考网上一篇文章重新整理了下屏幕双缓冲和DSA的知识!
⑴图形设置和图形上下文
应用程序绘制图形时,必须要使用图形设备和图形上下文。
图形设备是绘制操作的对象(如屏幕、打印机等),图形设备上下文提供了一种设备的抽象机制从而完全屏蔽了具体的图形设备,应用程序在使用这些图形设备时只需要和这些抽象的图形设备类交互即可,而不必考虑其具体的设备。
图形上下文是绘画平台及绘画所需要工具的集合体,它还包括平台的尺寸、方向、颜色和所有能实现绘画想象力的附件。
下面为Symbian中使用的图形设备及其功能,它们是实现绘画的基础。
图形设备 | 描述 |
CGraphicsDevice | 图形设备的基类 |
CBitmapDevice | 位图化图形设备的基类 |
CFbsDevice | 使用字体位图服务器的图形设备基类 |
CPrinterDevice | 具有打印功能的设备基类 |
CWsScreenDevice | 使用窗口服务器的屏幕设备 |
CFbsBitmapDevice | 使用字体位图服务器的设备具体实现 |
CFbsScreenDevice | 使用直接屏幕访问(DSA),而不通过窗口服务器 |
这些设备类的继承关系如下:
CWindowsGc用于屏幕绘制,CFbsBitGc则用于内存绘制!
⑵双缓冲
应用程序在屏幕上的描画一般是使用CWsScreenDevice图形设备来完成,与CWindowGc图形上下文相关联。CONE提供了一个CWindowGc实例作为描画控件的标准图形上下文。它被CCoeEnv创建并且可以使用CCoeControls::SystemGc()方法访问。 CWindowGc的描画方法在客户端窗口服务器缓冲区上进行缓冲。
void CExampleControl::Draw( const TRect& /*aRect*/ ) const { // Get the system graphics context CWindowGc& gc = SystemGc(); // Set drawing settings gc.SetBrushStyle( CGraphicsContext::ESolidBrush ); gc.SetBrushColor( KRgbRed ); // Draw gc.DrawLine( TPoint(10,10), TPoint(30,10) ); } |
DrawNow()强制控件立即重画自己,而DrawDeferred()导致一个重画事件使用低优先级操作!
如果一个游戏的图形由多个需要被经常更新的运动对象组成,窗口服务器的客户端缓冲可能被充满并且可能会在所有对象都更新的时候溢出,用户可能会发现屏幕出现闪烁。如果一个视图仍然在更新的时候,可能会出现闪烁或者其他不希望的效果。这些问题的解决方案是双缓冲,图形先被画在一个屏外位图上,然后被画到屏幕上作为一个单一窗口服务器操作。尤其是对于那种在一秒钟内重画几次屏幕的游戏,使用屏外位图可以改善它们的性能。
一个屏外位图可以使用位图化的图形上下文和图形设备类来创建:CFbsBitGc和CFbsBitmapDevice。它们使用其他的上下文和设备类来创建和使用。为了获得额外的性能,位图自己就应该是一个CWsBitmap位图。在屏外位图更新之后,它可以使用正常的窗口服务器的描画方法画在窗口中。
当一个应用程序在一个窗口画位图时,它转化为和窗口相同的显示模式。这是一个很消耗时间的操作,实质上可能降低描画的速度。因此把位图用于动画的游戏应该在动画开始之前就完成转化。转化可以通过使用一个屏外位图来执行,如下面的示例方法演示:
CFbsBitmap* CExampleControl::LoadAndConvertBitmapL( Const TDesC& aFileName, TInt aBitmapId ) { // Load the 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(newBitmap); CleanupStack::PushL( graphicsDevice ); CFbsBitGc* graphicsContext; User::LeaveIfError( graphicsDevice->CreateContext( graphicsContext ) ); TPoint zero(0,0); // Blit the loaded bitmap to the new bitmap graphicsContext->BitBlt( zero, originalBitmap ); CleanupStack::Pop(3); delete graphicsContext; delete graphicsDevice ; delete originalBitmap; return newBitmap; } |
示例方法使用一个文件名和位图ID作为参数,并且从一个MBM文件中装载相应的位图。如果一个游戏有许多位图应该转化,那么应该在游戏或者等级的初始化阶段转化,因此用户就不会看到这个操作了。
⑵直接屏幕访问(DSA)
使用窗口服务器在屏幕上描画需要一个上下文转换,这会减慢描画速度。为了绕过窗口服务器省去繁琐的上下文转换,可以直接访问屏幕。这被称作直接屏幕访问。
在Symbian OS中有两种方法来直接在屏幕上描画:
①CFbsScreenDevice是一个可以被发送到屏幕驱动程序SCDV.DLL的图形设备。在创建一个CFbsBitGc图形上下文之后,它能像任何其他的图形设备一样使用。然而,可以直接在屏幕上描画,而不需要使用窗口服务器。
②直接在屏幕上描画的另一种方法是从系统中查询屏幕内存地址,这可以使用UserSrv类来实现:
TPckgBuf<tscreeninfov01> infoPckg; <br>TScreenInfoV01& screenInfo = infoPckg(); <br>UserSvr::ScreenInfo(infoPckg); <br>TUint16* screenMemory = screenInfo.iScreenAddress + 16; </tscreeninfov01> |
屏幕内存有一个32字节的头。
即使在屏幕内存内写数据比CFbsScreenDevice稍微快一点,但是功能可能根据硬件和屏幕的设备驱动程序的不同而有差异。在一些基于Symbian OS的终端中,屏幕在内存变化的时候自动从屏幕内存中更新,而在其他的终端中描画需要明确的激活。屏幕内存地址只对目标硬件有效,因此描画代码需要分为硬件和模拟器两部分。在模拟器环境中,可以描画到一个屏外位图中,而不是屏幕内存中,然后使用正常的窗口服务器描画方法位块传送到屏幕上。环境可以通过使用__WINS__定义来检测出来。
#ifdef __WINS__ // Emulator environment
// Draw to an off-screen bitmap
#else // Hardware environment
// Draw directly to the screen memory
#endif
这两种直接描画方法的一个共同的问题是窗口服务器不了解描画,因此它不能通知应用程序是否出现另一个窗口或者窗口组。 即使当应用程序失去焦点的时候得到一个事件,它们也不能停止直接描画,因为直接描画实在太快了,并且屏幕内容有可能被弄乱。 这可能发生在玩游戏的时候,突然有电话打进来的情况下。
新近的GT 6.1版本提供了一个应用编程接口用于直接描画,将能解决前面提到的问题。
这个应用编程接口由两个类组成:一个MDirectScreenAccess类,提供用于应用程序的回调方法,还有一个CDirectScreenAccess类处理与窗口服务器的通讯。 下面的代码说明CDirectScreenAccess实例是如何构造的,以及直接描画支持是如何激活的。
iDrawer = CDirectScreenAccess::NewL(iEikonEnv->WsSession(), *iEikonEnv->ScreenDevice(), Window(), *this);
iEikonEnv->WsSession().Flush();
iDrawer->StartL();
iDrawer->ScreenDevice()->SetAutoUpdate(ETrue);
CDirectScreenAccess的NewL方法获得一个窗口服务器会话、CONE的图形设备、应用程序窗口和一个到MDirectedScreenAccess导出类的指针作为参数。 在CDirectScreenAccess::StartL被调用来激活直接描画支持之前,客户端窗口服务器缓冲应该溢出。 为了能自动更新屏幕,屏幕设备的SetAutoUpdate方法需要使用ETrue参数,否则gc draw指令不会在模拟器中立即显示,而是在下一次冲刷(Flush)视窗服务器时才显示。 当直接描画支持激活的时候,CDirectScreenAccess产生一个CFbsBitGc图形上下文,可以被应用程序用来在屏幕上绘画。
iDrawer->Gc()->BitBlt( TPoint(0,0), iBitmap );
当另一个窗口出现在应用程序窗口上时,CDirectScreenAccess从窗口服务器取得一个事件来中断描画。 CDirectScreenAccess然后调用MDirectScreenAccess派生类的AbortNow方法,这个方法必须被应用程序重载以便中断描画。 为了防止屏幕被弄乱,窗口服务器直到中断描画事件被处理的时候才画重叠窗口。
相关推荐
DSA数字签 DSA数字签DSA数字签名 DSA数字签名
Android DSA 官方使用说明 (转自网络,不完整,只是一个简单说明). p z9 I: h `8 X$ S: x* f 说明:Android DSA是由惠州善领科技有限公司独立开发,软件主要基于Android 2.1及以上平台的手机及MID上使用,支持320...
DSA善领最新数据
最新 DSA 数据
DSA速度变色版
善领 DSA 最新 电子眼数据 20140214,解压复制到DSA文件夹覆盖sound文件即可
DSA2013官方专业版,适合DSA导航仪使用
善领DSA
DSA自动运行DSA的自动运行 在DSA电子狗和凯立德地图共存的系统中,如果需要按导航仪上的GPS按钮就自动运行DSA,只需要修改DSA电子狗同一文件夹中的config.ini文件,在文件第一行添加autohide=0即可。
DSA加密算法的软件实现,此程序用c写成
[善领DSA] DSA2011最新P57最新升级的数据库 自带皮肤
善领DSA电子狗一向以其华丽的外表、实用的功能、快捷的服务为众多车友所喜爱。近日看到网上许多车友在苦苦寻找和不断寻问DSA皮肤修改问题,我像大家一样,经过无数次折腾,终于将网友放出的一些好看的皮肤修改成了...
DSA预警系统 dsa数据升级
DSA常用插件脚本
DSA数据自动升级工具,把工具拷贝到DSA目录,双击自动进行升级
DSA 233专业版数据 比普通版 播报的全一些。
最新DSA专业版236数据2013年05月15升级 解压后将sound.dat文件拷贝到dsa文件夹覆盖即可 (dsa免费版和黄金版主程序都可以使用) 黄金专业版和普通免费版区别 DSA专业版也就是黄金版,跟普通版也就是免费版的区别就...
DSA黄金手机版
dsa皮肤
这是标准的 DSA协议 ,共享给大家,希望给大家带来帮助!!