閱讀565 返回首頁    go 阿裏雲 go 技術社區[雲棲]


高級DirectDraw

使用高彩模式
上一章中說了可以用16位的色彩深度,但是16位的色彩深度的數據表示模式可以有兩種:Alpha.5.5.5(or X.5.5.5) 和 5.6.5(這是16位色彩最常用的)。對於使用哪種16位的色彩模式這個是由硬件決定的,我們不能決定。但是我們可以查詢,然後按照硬件支持的模式來填寫。
我們可以調用方法IDIRECTDRAWSURFACE7::GetPixelFormat(),同時這個函數需要一個LPDDPIXELFORMAT的結構,其中的dwFlags 和 dwRGBBitCount成員記錄著像素格式(8位索引或者RGB模式)
示例代碼如下:
DDPIXELFORMAT ddpixel;  
memset(&ddpixel, 0, sizeof(ddpixel) ); 
ddpixel.dwSize = sizeof(ddpixel);  
lpddsprimary->GetPixelFormat(&ddpixel);
                                   
if (ddpixel.dwFlags & DDPF_RGB)  // RGB Mode 
{   
        switch(ddpixel.dwRGBBitCount)   
        {   
                case 15:  // 5.5.5
                break;  
                case 16:  // 5.6.5    
                break;                                  
                case 24:                                         
                break;                    
                case 32:           
                break;           
                default:     
                break;        
        }       
}         
else  // ddpixel.dwFlags & DDPF_PALETTEINDEXED8 == TRUE
{           
             
}      
對於32位的模式也可以用以上判斷代碼,並且將填寫顏色的代碼寫在case 32:裏麵。
32位色彩的兩種模式為:Alpha.8.8.8 和 X.8.8.8。對於後麵的一種,建議將X的8位置為0。
雙緩衝
現在我們已經可以對表麵進行修改了。這樣也就是通過視頻控製器直接將每一幀都光柵化。這對於靜態圖像來說已經很好了。但是如果是動畫呢?可能就不是非常平滑。我們就需要使用雙緩衝技術。即先申請一個和主表麵同樣大小的數組(或者數據塊),將色彩數據填寫進這個數組中,最後再複製進加鎖的表麵中。在複製的時候我們需要注意表麵是否線形的問題。如果是線性的,那麼我們可以把整個數據塊一並複製;如果不是,那麼我們隻能一行行來複製。(其中這種技術我們並不會真正的用到,除非數據塊很小。因為DirectDraw提供給我們更好的動態表麵)
表麵動態
離屏表麵一——後備緩衝。創建後備緩衝的目的是用DirectDraw的方式來實現對雙緩衝功能的仿真。如果創建了DirectDraw後備緩衝(通常在VRAM中),讀寫會非常快。你可以將它和主表麵進行頁麵切換,這比雙緩衝方案下所需做的內存複製要快得多。
創建一個關聯有後備緩衝的主表麵步驟:
  1. 首先,你要將DDSD_BACKBUFFERCOUNT加到dwFlags標誌字段,向DirectDraw表明DDSURFACEDESC2結構的dwBackBufferCount字段有效,其中含有後備緩衝的數目。
  2. 其次,將控製標誌DDSCAPS_COMPLEX 和 DDSCAPS_FLIP加到DDSURFACEDESC2結構的特性描述字段ddsCaps.dwCaps上。
  3. 最後,像通常一樣創建主表麵。從它調用IDIRECTDRAWSURFACE7::GetAttachedSurface() 以得到後備緩衝。

示例代碼:

LPDIRECTDRAWSURFACE7 lpddsback;

ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;                                      
ddsd.dwBackBufferCount = 1;                                                                                         
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP;                                                                                                                    
lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL);                                                
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;                                                       
lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback);                    

注意其中紅色屬性。

這樣一來,以後隻要每次都在後備緩衝繪圖,然後調用Flip方法進行表麵切換,就可以實現快速的翻頁。

示例代碼:

lpddsprimary->Flip(NULL, DDFLIP_WAIT);

需要注意兩點,1.翻頁總是由主表麵執行的。2.翻頁前主表麵或者後備緩衝表麵都必須解鎖

使用Blitter

DirectDraw中在各個表麵之間進行Blitter和Windows編程中的各個DC之間Blt有點類似,不過DirectDraw中可以做的更加好,更加快。有兩個達到這個功能的函數:Blt() 和 BltFast()。他們的不同是前者會調用裁減器而後者不用但是速度更快。

示例代碼:

DDBLTFX ddbltfx;                                                           
RECT dest_rect;  
memset(&ddbltfx, 0, sizeof(ddbltfx));  
ddbltfx.dwSize = sizeof(ddbltfx);  
ddbltfx.dwFillColor = RGB(0, 0, 0);  // or color index in 8 bit mode 
dest_rect.left = x1; 
dest_rect.top = y1;  
dest_rect.right = x2;
dest_rect.bottom = y2; 
lpddsprimary->Blt(&dest_rect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT,  &ddbltfx);  

在上麵的例子中,調用Blt函數有兩個參數是NULL,因為這個例子比較特殊,他並沒有從另外一個已有表麵複製,而是用一種顏色對自己進行填充。這是Blt的一個特殊用法。一般情況下,我們總是從另外一個表麵(可能是離屏表麵)向目標表麵(可能是後備緩衝)進行填充。注意,函數調用的參數中的那個表麵是源表麵。

上麵Blt函數中的第一個NULL參數表示源表麵要複製過來的區域,那麼要是這塊區域對應到目標表麵的區域出現了問題怎麼辦?也就是說,他超出了整個目標表麵。如要從源(0,0, 100, 100)複製到目標的(600, 400, 700, 600)(這裏保持兩個RECT大小一樣,不一樣的情況以後會說),但是目標表麵隻有640*480的大小,也就是說沒有(700,600)這點,有一部分會超出表麵。所以這個時候我們隻要複製(600, 400, 640, 480)這樣一塊就可以了。其餘部分需要裁減掉。

裁減器

你需要做的就是創建一個IDirectDrawClipper,傳給它有效的裁減區域,然後將它同表明連接。具體步驟如下:

  1. 創建DirectDraw裁減器對象。
  2. 創建裁減序列。
  3. 用IDIRECTDRAWCLIPPER::SetClipList() 將裁減序列發送給裁減器。
  4. 用IDIRECTDRAWSURFACE7::SetClipper()將裁減器同窗口和/或表麵相關聯。

示例代碼:

LPDIRECTDRAWCLIPPER lpddclipper = NULL;
lpdd->CreateClipper(0, &lpddclipper, NULL);
lpddclipper->SetClipList(&rgndata, 0);
lpddsurface->SetClipper(&lpddclipper);

其中的rgndata變量是一個RGNDATA結構,這是一個動態的結構。由兩個成員(一個結構,一個指針)組成。用這個結構來創建裁減序列。

離屏表麵

接下來我們說一下離屏表麵(通用的非主表麵也非後備表麵)的創建。

基本同創建主表麵一樣,隻是對於ddsd結構的設置稍有以下不同。

  1. 你必須將ddsd.dwFlags設置為 DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT
  2. 你必須在ddsd.dwWidth, ddsd.dwHeight中設置所請求的表麵的尺寸。
  3. 必須將ddsd.dwCaps設置為DDSCAPS_OFFSCREENPLAIN | memory_flags,其中memory_flags決定在那裏創建表麵。

示例代碼:

LPDIRECTDRAWSURFACE lpdds;
DDRAW_INIT_STRUCT(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = 1024;
ddsd.dwHeight = 768;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
lpdd->CreateSurface(&ddsd, &lpdds, NULL);

這樣就創建了一個和主表麵兼容的離屏表麵。另外建議在創建離屏表麵的時候總是從大到小的創建。

現在你就可以像使用一般的表麵一樣來進行鎖定,位圖複製和Blitter操作了。

色彩鍵

當我們在複製位圖的時候可能其中的某些顏色(透明色)我們並不想複製。那麼我們就可以通過將他們設置成源色彩鍵。例如我們要把色彩0作為色彩鍵,可以這麼做:

示例代碼:

DDCOLORKEY color_key;
color_key.dwColorSpaceLowValue = 0;
color_key.dwColorSpaceHighValue = 0;
lpdds->SetColorKey(DDCKEY_SRCBLT, &color_key);

 

最後更新:2017-04-03 14:54:08

  上一篇:go Jquery checkbo自動填充選擇
  下一篇:go IDirectDraw接口