DirectX5.0最新遊戲程式設計指南 DirectDraw教程篇 二、第一個DirectDraw例項 (轉)
二、第一個DirectDraw例項
要使用DirectDraw,首先必須建立DirectDraw的一個例項來表徵上的顯示適配卡,然後使用介面方法來處理物件。另外還需要建立一個或多個DirectDrawSurface物件的例項來顯示遊戲。DDEX1首先建立一個DirectDraw物件,再建立一個主表面(primary surface)和一個後臺緩衝區(back buffer),然後在表面之間轉換。DDEXx例子都是用C++寫成的,如果你使用的是C,必須將程式碼做適當改動,至少要加入虛表和指向介面方法的指標。
1、首先初始化DirectDraw物件
DDEX1 在doInit包含了DirectDraw 的初始化程式碼:
// 建立主DirectDraw 物件
ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
if( ddrval == DD_OK )
{
// 獲取獨佔
ddrval = lpDD->SetCerativeLevel( hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
if(ddrval == DD_OK )
{
ddrval = lpDD->SetDisplayMode( 640, 480, 8 );
if( ddrval == DD_OK )
{
//建立帶有一個後臺緩衝區的主表面
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FL|
DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );
if( ddrval == DD_OK )
{
//獲取後臺緩衝區的指標
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval=lpDDSPrimary->GetAttachedSurface(&ddscaps, &lpDDSBack);
if( ddrval == DD_OK )
{
// 畫出一些文字
if (lpDDSPrimary->GetDC(&hdc) == DD_OK) {
SetBkColor( hdc, RGB( 0, 0, 255 ) );
SetTextColor( hdc, RGB( 255, 255, 0 ) );
TextOut( hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg) );
lpDDSPrimary->ReleaseDC(hdc);
}
if (lpDDSBack->GetDC(&hdc) == DD_OK) {
SetBkColor( hdc, RGB( 0, 0, 255 ) );
SetTextColor( hdc, RGB( 255, 255, 0 ) );
TextOut( hdc, 0, 0, szBackMsg, lstrlen(szBackMsg) );
lpDDSBack->ReleaseDC(hdc);
}
// 建立翻轉頁面的計時器
if( SetTimer( hwnd, TIMER_ID, TIMER_RATE, NULL ) )
{
return TRUE;
}
}
}
}
}
}
wsprintf(buf, "Direct Draw Init Failed (%08lx)n", ddrval );
............
下面詳細說明初始化DirectDraw 物件的建立和準備表面的每一步驟。
2、建立DirectDraw 物件
建立DirectDraw 物件的一個例項,應該用DirectDrawCreate 函式,也可以用COM中的CoCreateInstance函式。DirectDrawCreate用一個全域性統一標誌符GUID(Globally Unique ntifier)來表徵顯示裝置,在大多數情況下GUID為NULL(使用的預設顯示裝置,既“空裝置”);指標指向DirectDraw物件的地址;第三個引數總是NULL(供將來擴充套件使用)。下述程式碼表明瞭如何建立一個DirectDraw物件,並且檢驗是否成功。
ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
if( ddrval == DD_OK )
{
// lpDD is是合法的DirectDraw 物件
}
else
{
// DirectDraw物件不能被建立
}
3、設定顯示模式
設定DirectDraw 應用程式的顯示模式需要兩步:首先IDirectDraw::SetCooperativeLevel方法來設定該模式下的要求,一旦確定了要求,再用IDirectDraw::SetDisplayMode 方法來選擇顯示解析度。
在改變顯示解析度之前,還必須透過IDirectDraw::SetCooperativeLevel方法來指定DDSCL_EXCLUSIVE和DDSCL_FULLSCREEN 標誌。
這樣能使遊戲程式完全控制顯示裝置,其它的應用程式不能同時共享顯示裝置。DDSCL_FULLSCREEN標誌表示將程式設為全屏模式。下面的程式碼顯示瞭如何使用IDirectDraw::SetCooperativeLevel方法:
HRESULT ddrval;
LPDIRECTDRAW lpDD; // already created by DirectDrawCreate
ddrval = lpDD->SetCooperativeLevel( hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
if( ddrval == DD_OK ){
// 全屏獨佔方式設定成功
}
else {
// 呼叫不成功,但程式仍然能繼續執行
}
如果IDirectDraw::SetCooperativeLevel不返回DD_OK,你仍然可以執行該程式,但不是全屏模式,有時可能產生一些無法預料的錯誤。
因此你應該顯示一條錯誤資訊,讓知道發生了什麼事,由使用者來決定是否繼續執行遊戲。
使用IDirectDraw::SetCooperativeLevel時,必須向視窗 (HWND)傳送一個控制程式碼,讓視窗決定何時非正常地終止應用程式。例如,若發生了GP錯誤或GDI被翻轉(flip)到了後臺緩衝區,使用者就無法訪問當前螢幕。為了避免這種情況,DirectDraw有一個後臺等待程式,它俘獲所有發往該視窗的訊息,用這些訊息來確定應用程式何時終止。如果建立了新的視窗,必須確定該視窗為活動的,否則,就會有一系列的事件無法繼續工作。
4、改變顯示模式
一旦選擇了應用程式的工作模式,就可以使用IDirectDraw::SetDisplayMode方法來改變顯示模式,下面的程式碼將顯示模式設定成640x480x256:
HRESULT ddrval;
LPDIRECTDRAW lpDD; // already created
ddrval = lpDD->SetDisplayMode( 640, 480, 8 );
if( ddrval == DD_OK ) {
// 改變模式成功
}
else {
// 顯示模式不能改變
// 系統可能不支援該模式
}
當設定顯示模式時,應該確保如果使用者的裝置不支援更高的解析度,應用程式應該返回系統支援的標準模式。如果顯示示配卡不支援設計的解析度,IDirectDraw::SetDisplayMode返回一個DDERR_INVALIDMODE 錯誤值。因此,在設定解析度時,應該先用IDirectDraw::EnumDisplayMode方法檢測使用者的顯示裝置的。
5、建立可翻轉表面(Flippable Surface)
設定了顯示模式後,必須建立放置應用程式的表面。在DDEX1例中,我們使用IDirectDraw::SetCooperativeLevel 方法將程式設成獨佔全屏模式,然後可以建立翻轉表面。如果使用IDirectDraw::SetCooperativeLevel 設成DDSCL_NORMAL模式,就只能建立塊寫方式的表面了。
6、定義表面要求
建立可翻轉表面的的第一步是在DDSURFACEDESC結構中定義表面的要求。下面的程式碼描述了結構的定義及建立可翻轉表面所需要的標誌:
// 建立帶有一個後臺緩衝區的主表面
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
例中,成員變數dwSize被設為DDSURFACEDESC結構的大小。dwFlags標誌指定DDSURFACEDESC結構中哪些域可存放有效資訊。 在DDEX1例中,dwFlags指出了需要使用DDSCAPS結構(DDSD_CAPS)並建立一個後臺緩衝區 (DDSD_BACKBUFFERCOUNT)。dwCaps指出 DDSCAPS結構會用到的標誌,本例中它指定了一個主表面(DDSCAPS_PRIMARYSURFACE),一個翻轉表面(DDSCAPS_FLIP)和一個複雜表面 (DDSCAPS_COMPLEX)。最後,程式指定了一個後臺緩衝區。後臺緩衝區是背景影像和人物將寫入的位置,它可以轉化為主表面。
本例中,後臺緩衝區的數目為1,事實上,只要有足夠的顯示,可以建立任意多個後臺緩衝區,一般每1M的顯示記憶體只能用來建立一個後臺緩衝區。表面的記憶體既可以是顯示記憶體,也可以是系統記憶體。DirectDraw在使用完了顯示記憶體時(例如在僅有1M的顯示記憶體建立了2個後臺緩衝區)會自動使用系統記憶體。你可以透過將DDSCAPS結構中的dwCaps設定為DDSCAPS_SYSTEMMEMORY或
DDSCAPS_VIDEOMEMORY來指定只使用系統記憶體或只使用顯示記憶體。如果指定了 DDSCAPS_VIDEOMEMORY又沒有足夠的顯示記憶體來建立表面,IDirectDraw::CreateSurface 將返回一個DDERR_OUTOFVIDEOMEMORY錯誤。
7、建立表面
填完了DDSURFACEDESC結構,就可以使用該結構和lpDD了,lpDD是用DirectDrawCreate 方法建立的DirectDraw 物件的指標,下面的程式碼顯示了這一過程:
ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );
if( ddrval == DD_OK ) {
// lpDDSPrimary points to new surface
}
else{
// surface was not created
return FALSE;
}
如果呼叫成功,IDirectDraw::CreateSurface函式就返回指向主表面的指標lpDDSPrimary 。若主表面指標可用,就可以呼叫
IDirectDrawSurface::GetAttachedSurface 方法取得後臺緩衝區的指標,如下所示:
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval = lpDDSPrimary->GetAttachedSurface( &ddcaps, &lpDDSBack );
if( ddrval == DD_OK ) {
// lpDDSBack points to the back buffer
}
else{
return FALSE;
}
如果IDirectDrawSurface::GetAttachedSurface呼叫成功,透過提供主表面的地址和設定DDSCAPS_BACKBUFFER 標誌,lpDDSBack 引數就指向後臺緩衝區。
8、著色表面
建立了主表面和後臺緩衝區後,DDEX1使用標準的 GDI 函式將一些文字提交到主表面和後臺緩衝區,程式碼如下:
if (lpDDSPrimary->GetDC(&hdc) == DD_OK){
SetBkColor( hdc, RGB( 0, 0, 255 ) );
SetTextColor( hdc, RGB( 255, 255, 0 ) );
TextOut( hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg) );
lpDDSPrimary->ReleaseDC(hdc);
}
if (lpDDSBack->GetDC(&hdc) == DD_OK){
SetBkColor( hdc, RGB( 0, 0, 255 ) );
SetTextColor( hdc, RGB( 255, 255, 0 ) );
TextOut( hdc, 0, 0, szBackMsg, lstrlen(szBackMsg) );
lpDDSBack->ReleaseDC(hdc);
}
例中使用了IDirectDrawSurface::GetDC方法來裝置上下文的控制程式碼且鎖定該表面。如果不想使用要求控制程式碼的Windows函式,還可以使用IDirectDrawSurface::Lock和IDirectDrawSurface::Unlock 方法來鎖定和解鎖後臺緩衝區。鎖定表面的記憶體(不管是整個表面還是其中的一部分)能確保你的應用程式和系統不會同時訪問這塊記憶體。另外,除非給記憶體解鎖,程式不能翻轉表面。本例在鎖定表面後使用Windows GDI 函式SetBkColor來設定背景顏色,使用SetTextColor來設定文字顏色,然後使用TextOut將文字輸出到表面。當文字寫入緩衝區後,例中使用了IDirectDrawSurface::ReleaseDC方法來解鎖表面並釋放控制程式碼。良好的習慣是,向後臺緩衝區寫資料完成後,馬上呼叫IDirectDrawSurface::ReleaseDC或IDirectDrawSurface::Unlock。
一般來講,當向表面寫資料時,該表面就是後臺緩衝區,然後將緩衝區翻轉成主表面顯示出來。在DDEX1中,第一次翻轉表面之前有一個重要的延遲。於是DDEX1就將資料寫入主緩衝區,避免開始顯示時有太長的時間間隔。後面將會講到,DDEX1只在 WM_TIMER期間向後臺寫資料。初始化函式或標題頭可能會寫入主緩衝區。應該注意的是,一旦使用IDirectDrawSurface::Unlock對錶面解鎖,指向表面的指標就變成無效,必須再次使用IDirectDrawSurface::Lock方法才能獲取該表面記憶體的有效指標。
9、寫表面及翻轉表面
完成了初始化後,DDEX1開始處理訊息迴圈。在訊息迴圈的過程中,完成鎖定後臺緩衝區——寫入新的文字——解鎖後臺緩衝區——翻轉表面的過程。WM_TIMER包含了寫資料和翻轉表面的大部分程式碼。
WM_TIMER訊息的前半部分用於向後臺緩衝區寫資料,“phase”變數決定是寫主緩衝區訊息還是寫後臺緩衝區訊息。如果phase為1,表示寫主緩衝區的訊息,然後將phase改變為0;若為0,表示寫後臺緩衝區的訊息,然後將phase改變為1。注意,兩種情況中的訊息都是寫向後臺緩衝區。後臺緩衝區寫入了訊息後,使用IDirectDrawSurface::ReleaseDC方法解鎖。下面的程式碼實現了這一點:
case WM_TIMER:
// Flip surfaces
if( bActive ) {
if (lpDDSBack->GetDC(&hdc) == DD_OK)
{
SetBkColor( hdc, RGB( 0, 0, 255 ) );
SetTextColor( hdc, RGB( 255, 255, 0 ) );
if( phase ) {
TextOut( hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg) );
phase = 0;
}
else {
TextOut( hdc, 0, 0, szBackMsg, lstrlen(szBackMsg) );
phase = 1;
}
lpDDSBack->ReleaseDC(hdc);
}
表面記憶體解鎖後,使用IDirectDrawSurface::Flip方法將後臺緩衝區翻轉成主表面,程式碼如下:
while( 1 ) {
HRESULT ddrval;
ddrval = lpDDSPrimary->Flip( NULL, 0 );
if( ddrval == DD_OK )
{
break;
}
if( ddrval == DDERR_SURFACELOST )
{
if(ddrval = lpDDSPrimary-&g>val != DD_OK )
{
break;
}
}
if( ddrval != DDERR_WASSTILLDRAWING )
{
break;
}
}
例中,lpDDSPrimary指明瞭主表面及其後臺緩衝區。呼叫IDirectDrawSurface::Flip方法後,主表面和後表面。呼叫成功後,返回DD_OK,程式終止While迴圈;如果返回DDERR_SURFACELOST,表明可能是表面丟失,需要用IDirectDrawSurface::Restore 方法恢復該表面,若恢復成功,就再一次呼叫IDirectDrawSurface::Flip方法;如果失敗,程式終止While迴圈並返回一個錯誤值。另外,如前所述,即
使呼叫IDirectDrawSurface::Flip成功,交換也不是立即完成,它將等到系統中在此之前的表面交換都完成後才進行。例如,前一次的表面翻轉還未發生時,IDirectDrawSurface::Flip 就返回DDERR_WASSTILLDRAWING。本例中,IDirectDrawSurface::Flip繼續迴圈直到返回DD_OK.。
10、釋放DirectDraw 物件
當按了F12後,DDEX1程式在退出之前先處理WM_DESTROY訊息,該訊息呼叫了finis函式,而finiObjects函式包含了所有的IUnknown Release的呼叫,程式碼如下:
static void finiObjects( void ){
if( lpDD != NULL ) {
if( lpDDSPrimary != NULL ) {
lpDDSPrimary->Release();
lpDDSPrimary = NULL;
}
lpDD->Release();
lpDD = NULL;
}
} /* finiObjects */
程式檢測DirectDraw物件的指標(lpDD)和DirectDrawSurface物件的指標(lpDDSPrimary) 是否等於NULL,本例中顯然不為NULL。然後DDEX1呼叫 IDirectDrawSurface::Release方法將DirectDrawSurface 物件的參考值減1,這將會使得其參考值變為0,DirectDrawSurface 物件就被釋放了,DirectDrawSurface的指標被設為NULL值,然後撤消。程式又呼叫IDirectDraw::Release就DirectDraw物件的參考值減1變為0,釋放DirectDraw物件及其指標。
上述的DDEX1是DirectDraw最基本的應用,它首先建立DirectDraw物件和DirectDrawSurface物件,建立一個主表面及其後臺緩衝區,將文字輸出到後臺緩衝區,然後轉化表面。第二個例子DDEX2擴充套件了DDEX1的功能,它可以將一個點陣圖調入後臺緩衝區。第三個例子DDEX3 則更進一步,除了一個主表面及後臺緩衝區外,還建立了兩個屏外表面,將點陣圖調入每一個屏外表面,然後使用IDirectDrawSurface::BltFast方法將一個屏外表面的內容位塊傳輸到後臺緩衝區,然後翻轉表面並將另一個屏外表面的內容位塊傳輸到後臺緩
衝區。下面將詳細討論這些功能。
11、將點陣圖調入表面
如DDEX1中一樣,doInit函式是DDEX2的初始化函式,兩者的實質一樣,一直到下面的程式碼:
lpDDPal = DDLoadPalette(lpDD, szBackground);
if (lpDDPal == NULL)
goto error;
ddrval = lpDDSPrimary->SetPalette(lpDDPal);
if( ddrval != DD_OK )
goto error;
// load a bitmap into the back buffer.
ddrval = DDReLoaitmap(lpDDSBack, szBackground);
if( ddrval != DD_OK )
goto error;
程式碼的第一行從函式DDLoadPalette返回一個值,該函式在C: DX5SDKSDKSAMPLESMISC中的Ddutil.cpp檔案中,因此編譯DDEX2時需要將Ddutil.cpp和Ddutil.h加入過程。大部分的DirectDraw程式都需要該檔案。在DDEX2中,DDLoadPalette函式從Back.bmp檔案中建立一個DirectDrawPalette物件。DDLoadPalette函式首先檢查用於建立調色盤的檔案或資源十分存在,如果不存在,就建立一個預設調色
板。在DDEX2中,它從位件中抽取調色盤資訊並在由ape指向的結構,然後如下建立 DirectDrawPalette物件:
pdd->CreatePalette(DDPCAPS_8BIT, ape, &ddpal, NULL);
return ddpal;
當IDirectDraw::CreatePalette方法返回時,ddpal就指向該DirectDrawPalette物件。ape是指向一個結構的指標,該結構能包含2/4/16/256個線性的實體,實體的數目由IDirectDraw::CreatePalette 呼叫的dwFlags引數決定。本例中,dwFlags設定為DDPCAPS_8BIT,這表示該結構中有256個實體,每個實體有四個位元組(紅色、綠色、藍色和標誌位元組)。
12、設定調色盤,將點陣圖調入後臺緩衝區
建立了調色盤之後,可以透過呼叫IDirectDrawSurface::SetPalette 方法將DirectDrawPalette 物件的指標ddpal傳送給主表面,程式碼如下:
ddrval = lpDDSPrimary->SetPalette(lpDDPal);
if( ddrval != DD_OK )
// SetPalette failed
呼叫了IDirectDrawSurface::SetPalette方法之後,DirectDrawPalette物件就和DirectDrawSurface物件掛(hook)在一起了,需要改變調色盤時,只需要建立一個新的調色盤對其進行設定就可以了。
DirectDrawPalette物件同DirectDrawSurface物件掛在一起後,DDEX2使用以下程式碼將Back.bmp檔案裝入後臺緩衝區:
// load a bitmap into the back buffer.
ddrval = DDReLoadBitmap(lpDDSBack, szBackground);
if( ddrval != DD_OK )
// Load failed
DDReLoadBitmap是Ddutil.cpp中的另一個函式,它將點陣圖從檔案或資源中調入已經存在的DirectDraw表面。在本例中,它將szBackground指向的Back.bmp裝入lpDDSBack指向的後臺緩衝區。DDReLoadBitmap呼叫DDCopyBitmap函式將檔案複製到後臺緩衝區並延展為適當的尺寸。DDCopyBitmap函式將點陣圖拷入記憶體,使用GetObject函式獲取點陣圖的大小,然後用下述程式碼獲取將要放置點陣圖的後臺緩衝區的大小:
// get size of surface.
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
pdds->GetSurfaceDesc(&ddsd);
ddsd 是指向DDSURFACEDESC結構的指標,該結構儲存了DirectDraw表面的當前描述。DDSURFACEDESC 結構的成員描述了由DDSD_HEIGHT 和DDSD_WIDTH指定了表面的高和寬。IDirectDrawSurface::GetSurfaceDesc方法使用合適的值調入結構,例中高為480,寬為640。DDCopyBitmap函式鎖定表面並將點陣圖複製到後臺緩衝區,然後用StretchBlt函式對點陣圖進行拉伸或,程式碼如下:
if ((hr = pdds->GetDC(&hdc)) == DD_OK){
StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, x, y, dx, dy, SRCCOPY);
pdds->ReleaseDC(hdc);
}
13、從屏外表面位塊傳輸
DDEX2同DDEX1基本相同。DDEX2開啟一個點陣圖檔案並將它送往後臺緩衝區,然後翻轉後臺緩衝區和主表面。但這對顯示點陣圖並不特別理想,DDEX3擴充套件了DDEX2的功能,它加入了兩個屏外緩衝區,每個緩衝區都儲存一個點陣圖。下面是DDEX3中的doInit函式的一部分,功能是建立兩個屏外緩衝區:
// Create an offscreen bitmap.
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwHeight = 480;
ddsd.dwWidth = 640;
ddrval = lpDD->CreateSurface( &ddsd, &lpDDSOne, NULL );
if( ddrval != DD_OK ){
return initFail(hwnd);
}
// Create another offscreen bitmap.
ddrval = lpDD->CreateSurface( &ddsd, &lpDDSTwo, NULL );
if( ddrval != DD_OK ){
return initFail(hwnd);
}
從程式碼中可以看到,dwFlags指明瞭程式使用DDSCAPS結構,並設定緩衝區的高和寬。由DDSCAPS 結構中的DDSCAPS_OFFSCREEN 標誌指定該表面是屏外緩衝區,在DDSURFACEDESC結構中將高和寬設為480和640,然後使用IDirectDraw::CreateSurface方法來建立表面。因為兩個屏外表面的大小一樣,建立第二個緩衝區只需要再執行一次IDirectDraw::CreateSurface即可(當然要用不同的指標)。你還可以在DDSCAPS 中設定DDSCAPS_SYSTEMMEMORY或DDSCAPS_VIDEOMEMORY 來指定屏外緩衝區放在顯示記憶體還是系統記憶體。將點陣圖存放在顯示記憶體可以加快後臺緩衝區與屏外表面之間的資料傳輸速度,這在點陣圖動畫中非常重要。但是,如果你為屏外緩衝區指定了DDSCAPS_VIDEOMEMORY又沒有足夠的顯示記憶體調入整個點陣圖,當建立該表面時,程式就會返回一個DDERR_OUTOFVIDEOMEMORY的錯誤值。
14、將點陣圖檔案調入屏外表面
建立了兩個屏外表面後,DDEX3使用了InitSurfaces函式將點陣圖從Frntback.bmp檔案裝入到兩個表面。InitSurfaces函式使用了DDCopyBitmap函式調入兩個點陣圖,程式碼如下:
// Load our bitmap re.
hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), szBitmap,
IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
if (hbm == NULL)
return FALSE;
DDCopyBitmap(lpDDSOne, hbm, 0, 0, 640, 480);
DDCopyBitmap(lpDDSTwo, hbm, 0, 480, 640, 480);
DeleteObject(hbm);
return TRUE;
Frntback.bmp檔案由兩部分組成,一半在上,一半在下。DDCopyBitmap函式將上半部分調入第一個屏外表面lpDDSOne,下半部分調入第
二個表面lpDDSTwo。
15、將屏外表面位位塊傳輸到後臺緩衝區
WM_TIMER包含了寫表面和翻轉表面的程式碼。在DDEX3中,它選擇適當的屏外表面,並將其位塊傳輸到後臺緩衝區,程式碼如下:
rcRect.left = 0;
rcRect.top = 0;
rcRect.right = 640;
rcRect.bottom = 480;
if(phase)
{
pdds = lpDDSTwo;
phase = 0;
}
else {
pdds = lpDDSOne;
phase = 1;
}
while( 1 ) {
ddrval = lpDDSBack->BltFast( 0, 0, pdds, &rcRect, FALSE );
if( ddrval == DD_OK )
{
break;
}
“phase”決定了準備將哪一個屏外表面位塊傳輸到後臺緩衝區,然後呼叫IDirectDrawSurface::BltFast方法將選定的屏外表面位塊傳輸到後臺緩衝區,從左上角的位置0,0開始。rcRect指向定義了屏外表面的左上角和右下角的RECT結構。最後一個引數設為FALSE或0,指明不使用特殊的傳輸標誌。一旦屏外表面被傳送到後臺緩衝區,就可以利用前面的方法將後臺緩衝區和主表面相互翻轉了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-987894/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- VC++視覺化程式設計第一個程式設計例項出錯C++視覺化程式設計
- 遊戲程式設計入門指南遊戲程式設計
- 最新SS園設計模式例項剖析與深入解讀教程設計模式
- windows10系統無法禁用DirectDraw的解決方法Windows
- 10個最新互動式Web設計例項欣賞Web
- Win10系統下DirectDraw導致閃屏怎麼解決Win10
- KafKa Java程式設計例項KafkaJava程式設計
- 設計模式例項程式碼設計模式
- Jmeter beanshell程式設計例項JMeterBean程式設計
- C++設計模式+例項視訊教程C++設計模式
- Rust 程式設計影片教程(進階)——010_2Box 使用例項Rust程式設計
- 如何設計遊戲教程遊戲
- CSS匹配第一個li元素程式碼例項CSS
- 課時2:用python設計第一個遊戲Python遊戲
- Dreamweaver網頁製作教程:表格設計例項網頁
- 「SSM框架最新專案」搭建個人部落格例項講解教程SSM框架
- Rust 程式設計視訊教程(進階)——010_2Box 使用例項Rust程式設計
- CSS-Flex 佈局教程:例項篇CSSFlex
- 如何根據自己的需要培養遊戲開發技能?又一篇遊戲程式設計入門指南遊戲開發程式設計
- JAVA程式設計注意事項(效能篇)Java程式設計
- 網頁倒數計時跳轉程式碼例項網頁
- Python教程系列(一)—— Python基礎教程之第一個程式設計練習Python程式設計
- ts學設計模式: 第一篇: 單例模式設計模式單例
- shell script程式設計小結——附帶例項程式設計
- Spark程式設計環境搭建及WordCount例項Spark程式設計
- 遊戲大地圖開發指南:遊戲外部空間設計遊戲地圖
- Unity遊戲框架設計之單例MonoUnity遊戲框架單例Mono
- TGDC | 一個遊戲程式設計師的堅持 —— 論向量化程式設計遊戲程式設計師
- 測試用例設計指南
- 轉載:SpringBoot非官方教程 | 第一篇:構建第一個SpringBoot工程Spring Boot
- 遊戲程式設計模式學習:第一章命令模式遊戲程式設計設計模式
- Java例項教程Java
- ORM 例項教程ORM
- 為遊戲設計湧現式玩法的五個注意事項遊戲設計
- 安利一個好玩的JS程式設計遊戲—warriorjsJS程式設計遊戲
- 【乾貨】遊戲介面設計 (二)結構設計遊戲
- [翻譯]返回導向程式設計例項入門程式設計
- 遊戲技能該如何設計?這二篇乾貨帶你瞭解遊戲
- keras轉tensorflow lite【方法二】直接轉:簡單模型例項Keras模型