GDI雙緩衝之道

圖形界面編程,常見棘手問題就是出現繪圖出現閃屏。這一現象也嚴重影響用戶體驗。前段時間剛接觸minigui就出現一個閃屏半天不得其解的一個問題,查了很多網絡資料使用方法都盡人意。

雙緩衝繪圖原理:

雙緩衝

雙緩衝的原理可以這樣形象的理解:把電腦屏幕看作一塊黑板。首先我們在內存環境中建立一個“虛擬“的黑板,然後在這塊黑板上繪製複雜的圖形,等圖形全部繪製完畢的時候,再一次性的把內存中繪製好的圖形“拷貝”到另一塊黑板(屏幕)上。採取這種方法可以提高繪圖速度,極大的改善繪圖效果。下面是原理圖:

圖一 雙緩衝原理示意圖

minigui關於DC

內存 DC 和 BitBlt
    新的 GDI 函數增強了內存 DC 操作函數。GDI 函數在建立內存 DC 時,將調用 GAL 的相應接口。如前所述,GAL 將盡量把內存 DC 建立在顯示卡的顯示內存當中。這樣,可以充分利用顯示卡的硬件加速功能,實現顯示內存中兩個不同區域之間位塊的快速移動、複製等等,包括透明處理和 Alpha 混和。應用程序可以建立一個具有逐點 Alpha 特性的內存 DC(每個點具有不同的 Alpha 值),也可以通過 SetMemDCAlpha 設置內存 DC 所有象素的 Alpha 值(或者稱爲"Alpha 通道"),然後利用 BitBlt 和 StretchBlt 函數實現 DC 之間的位塊傳送。應用程序還可以通過 SetMemDCColorKey 函數設置源 DC 的透明色,從而在進行 BitBlt 時跳過這些透明色。 

有關內存 DC 的 GDI 函數有(include/gdi.h): 
#define MEMDC_FLAG_NONE         0x00000000          /* None. */
#define MEMDC_FLAG_SWSURFACE    0x00000000          /* DC is in system memory */
#define MEMDC_FLAG_HWSURFACE    0x00000001          /* DC is in video memory */
#define MEMDC_FLAG_SRCCOLORKEY  0x00001000          /* Blit uses a source color key */
#define MEMDC_FLAG_SRCALPHA     0x00010000          /* Blit uses source alpha blending */
#define MEMDC_FLAG_RLEACCEL     0x00004000          /* Surface is RLE encoded */ 
HDC GUIAPI CreateCompatibleDC (HDC hdc);
HDC GUIAPI CreateMemDC (int width, int height, int depth, DWORD flags,
                Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
BOOL GUIAPI ConvertMemDC (HDC mem_dc, HDC ref_dc, DWORD flags);
BOOL GUIAPI SetMemDCAlpha (HDC mem_dc, DWORD flags, Uint8 alpha);
BOOL GUIAPI SetMemDCColorKey (HDC mem_dc, DWORD flags, Uint32 color_key);
void GUIAPI DeleteMemDC (HDC mem_dc); 

CreateCompatibleDC 函數創建一個和給定 DC 兼容的內存 DC。兼容的含義是指,新創建的內存 DC 的象素格式、寬度和高度與給定 DC 是相同的。利用這種方式建立的內存 DC 可以快速 Blit 到與之兼容的 DC 上。 

    這裏需要對象素格式做進一步解釋。象素格式包含了顏色深度(即每象素點的二進制位數)、調色板或者象素點中 RGBA(紅、綠、藍、Alpha)四個分量的組成方式。其中的 Alpha 分量,可以理解爲一個象素點的透明度,0 表示完全透明,255 表示完全不透明。在 MiniGUI 中,如果顏色深度低於 8,則 GAL 會默認創建一個調色板,並且可以調用 SetPalette 函數修改調色板。如果顏色深度高於 8,則通過四個變量分別指定象素點中 RGBA 分量所佔的位。如果是建立兼容 DC,則兼容內存 DC 和給定 DC 具有一樣的顏色深度,同時具有一樣的調色板或者一樣的 RGBA 分量組成方式。 

    如果調用 CreateMemDC 函數,則可以指定新建內存 DC 的高度、寬度、顏色深度,以及必要的 RGBA 組成方式。在 MiniGUI 中,是通過各自在象素點中所佔用的位掩碼來表示 RGBA 四個分量的組成方式的。比如,如果要創建一個包含逐點 Alpha 信息的16 位內存 DC,則可以用每分量四個二進制位的方式分配 16 位的象素值,這樣,RGBA 四個分量的掩碼分別爲:0x0000F000, 0x00000F00, 0x000000F0, 0x0000000F。 

    ConvertMemDC 函數用來將一個任意的內存 DC 對象,根據給定的參考 DC 的象素格式進行轉換,使得結果 DC 具有和參考 DC 一樣的象素格式。這樣,轉換後的 DC 就能夠快速 Blit 到與之兼容的 DC 上。 

    SetMemDCAlpha 函數用來設定或者取消整個內存 DC 對象的 Alpha 通道值。我們還可以通過 MEMDC_FLAG_RLEACCEL 標誌指定內存 DC 採用或者取消 RLE 編碼方式。Alpha 通道值將作用在 DC 的所有象素點上。 

    SetMemDCColorKey 函數用來設定或者取消整個內存 DC 對象的 ColorKey,即透明象素值。我們還可以通過 MEMDC_FLAG_RLEACCEL 標誌指定內存 DC 採用或者取消 RLE 編碼方式。 

剛開始嘗試創建兼容DC來嘗試解決此問題但是效果還是閃屏,最後採用單獨創建DC 函數: CreateMemDC 得以解決

	hdc = BeginPaint (hwnd);
			GetClientRect (hwnd, &rc);

			//hdcMem = CreateCompatibleDC (hdc ); 
			//hdcMem = CreateCompatibleDCEx(hdc,RECTW(rc), RECTH(rc));
			//hdcMem = CreateMemDC( RECTW(rc), RECTH(rc), 16,MEMDC_FLAG_HWSURFACE |MEMDC_FLAG_SRCALPHA ,
			//0x0000F000, 0x00000F00, 0x000000F0, 0x000000F );
  			  hdcMem = CreateMemDC (RECTW(rc), RECTH(rc), 32, MEMDC_FLAG_HWSURFACE | MEMDC_FLAG_SRCALPHA | MEMDC_FLAG_SRCCOLORKEY,
                    0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000);

		//	subMenuData = (subMenuData_t*)GetWindowAdditionalData(hwnd);
			//pWin->we_rdr->draw_header(hwnd,hdcMem,(const RECT*)&rc,0xFF808080);
					
			//SetWindowBkColor(hwnd, gp_normal_bgc);
		//	SetBrushColor (hdcMem, 0xFF808080);
		//	FillBox (hdcMem, 0, 0, RECTW(rc), RECTH(rc));
			pData = (PLISTBOXDATA)pCtrl->dwAddData2;			
			SelectFont(hdcMem, GetWindowFont(hwnd));
			lstOnDrawSListBoxItems (hwnd, hdcMem, pData, RECTW (rc));
			lstDrawFocusRect (hwnd, hdcMem, pData);
		
			BitBlt (hdcMem, 0, 0, RECTW(rc), RECTH(rc),hdc , 0, 0, 0); 
			//DeleteCompatibleDC (hdcMem); 
			EndPaint (hwnd, hdc);
			DeleteMemDC( hdcMem );






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