CGraphicsDevice && CGraphicsContext

⑴圖形設置和圖形上下文

       應用程序繪製圖形時,必須要使用圖形設備和圖形上下文。

       圖形設備是繪製操作的對象(如屏幕、打印機等),圖形設備上下文提供了一種設備的抽象機制從而完全屏蔽了具體的圖形設備,應用程序在使用這些圖形設備時只需要和這些抽象的圖形設備類交互即可,而不必考慮其具體的設備。

       圖形上下文是繪畫平臺及繪畫所需要工具的集合體,它還包括平臺的尺寸、方向、顏色和所有能實現繪畫想象力的附件。

       下面爲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; 
TScreenInfoV01& screenInfo = infoPckg(); 
UserSvr::ScreenInfo(infoPckg); 
TUint16* screenMemory = screenInfo.iScreenAddress + 16;
屏幕內存有一個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方法,這個方法必須被應用程序重載以便中斷描畫。 爲了防止屏幕被弄亂,窗口服務器直到中斷描畫事件被處理的時候才畫重疊窗口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章