亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

在CB中進行DirectX編程

2019-11-17 05:24:53
字體:
來源:轉載
供稿:網友
C++ Builder是一個可視化的C++編程環境,它為編程人員提供了一種方便高效、簡便的C++語言開發工具,因此已為廣大C++程序員所青睞,DirectX開發工具包是微軟公司提供的一套Windows9X下開發高性能圖形、聲音、輸入輸出和網絡游戲的接口,其高效的直接硬件訪問、程序與硬件設備之間的相對獨立等特性,幾乎使得DirectX成為唯一可以在Windows操作系統下開發游戲程序的基本工具軟件。
雖然C++ Builder中直接包含了一套DirectX3的開發包,也提供了一些例程,但是這些例程沒有系統化的說明,同時也不適合DirectX5以上的程序開發。另一方面,幾乎所有關于DirectX開發的書籍和文獻均使用Visual C++語言描述,所以作者將自己在C++ Builder中的一些開發經驗介紹給讀者。

本文適合具備C++ Builder面向對象編程經驗的讀者,實例開發環境為中文Windows98、C++ Builder4、DirectX6或以上的開發工具包。

一.DirectX簡介

1_1.DirectX的特性

1_2.DirectX是一種Windows環境下標準的高性能游戲、多媒體開發工具包,使用DirectX開發的程序能夠與操作系統默契地配合成為“真正”的桌面應用程序;可以利用硬件廠商提供的驅動程序接口,充分最佳的設備性能;通過直接底層硬件操作,實現最快速、短延時、設備無關的底層接口。

1_3.DirectX采用了組件對象模型(COM)標準,因此對于不同對象的版本可以有不同的接口,這使得用DirectX開發的程序在未來將得到完全兼容和支持的保證。

1_4.DirectX的結構

DirectX需要以設備無關的方法提供設備相關的性能,所以DirectX的結構是由兩個驅動程序構成:硬件抽象層(HAL)和硬件模擬層(HEL),當Direct對象創建時,會同時建立一張“兼容表”,其中記錄了當前硬件系統支持的功能,當DirectX需要實現某個功能時就查詢該表,得到硬件對功能的支持信息,假如功能能夠得到硬件支持,則向HAL發出求,以得到硬件的支持,否則向HEL發出請求,以模擬方式實現功能。

1_5.DirectX的主要組成

 

(1)DirectDraw:直接訪問圖形硬件,治理用于顯示的內存(顯示內存和系統內存),提供高速圖形和頁面切換動畫;

(2)Direct3D:提供3D硬件接口;

(3)DirectInput:主要支持輸入服務,同時支持輸出設備;

(4)DirectSound:提供3D聲音效果,治理聲卡內存;

(5)DirectPlay:提供網絡多人游戲的通訊、組織功能;

(6)DirectSetup:自動安裝DirectX驅動程序。

本文將按照DirectX的上述組成,分別以實例介紹其在C++ Builder中的實現方法。

 

 

二.DirectDraw程序設計

 

2.1 DirectDraw實現的基礎—顯示方式的設置

設計圖形程序首先碰到的問題是將屏幕設置成一種合適的圖形顯示方式,然后把圖形繪畫到屏幕頁面上。假如您在DOS下開發圖形應用程序,這將是很簡單的事,只要調用DOS的中斷服務程序即可實現,但是使用用DirectDraw就比較復雜。由于DirectDraw的設計目標是提供設備無關的編程接口和高效、多功能的硬件訪問支持,所以DirectDraw需要考慮更多的問題。

DirectDraw在Windows環境下支持兩種圖形方式:全屏幕獨占方式和窗口方式。這里我先以全屏幕獨占方式,介紹DirectDraw設置屏幕顯示方式步驟,函數具體使用格式和編程方法將在2.2中介紹:

2.1.1 選擇硬件設備

計算機系統不一定只有一個DirectDraw硬件抽象設備,例如,一臺計算機可能有兩臺或更多的顯示器,那么DirectDraw對象與哪個HAL對應呢?我們可以使用DirectDrawEnumerate函數來枚舉系統所有已安裝的設備,以供選擇,并返回設備的唯一標識GUID。DirectDraw默認主顯示設備的GUID為NULL;

2.1.2 創建DirectDraw對象

由于DirectX是使用面向對象的程序設計技術,因此,使用DirectDraw編程就首先要創建DirectDraw對象。使用DirectDrawCreate函數及將第一步獲得的設備GUID作為參數可以創建基于所選設備的DirectDraw對象;

2.1.3 獲取DirectDraw更高版本的COM接口

假如您不打算使用DirectX5以上版本提供的功能則可以跳過本步驟,否則必須使用新創建DirectDraw對象的QueryIntrface方法來獲得IDirectDraw2或更高的COM接口。在2.2例中將介紹如何獲得DirectX5以上版本提供的IDirectDraw2接口;

2.1.4 設置協作級別

協作方式可以控制程序與系統其他應用程序之間的交互關系,典型的例子是:設置為全屏獨占方式還是窗口普通方式。設置協作級別可以用DirectDraw對象的SetCoOperativeLevel方法;

2.1.5 枚舉設備支持的各種顯示方式,選擇并設置合適的顯示分辯率、色彩深度和刷新頻率等。

使用DirectDraw的EnumDisplayModes方法可以枚舉設備支持的所有圖形方式供用戶選擇,在某些已確定圖形顯示方式的應用程序中可以通過此枚舉功能來檢查系統設備是否支持指定的圖形顯示方式。

使用DirectDraw的SetDisplayMode方法可以設置所需要的圖形顯示方式。

 

2.2 用DirectDraw設置屏幕圖形顯示方式的實例

現在我們開始編寫第一個示例程序“設置全屏幕獨占圖形顯示方式的程序”dx1,首先我們將在這里討論C++ Builder中進行DirectX編程的有關問題,然后再具體介紹實現程序每一步驟的相關技術。

2.2.1 dx1程序運行過程介紹

dx1是根據DirectDraw設置屏幕圖形方式的過程設計的,運行界面如圖2.1所示。在窗口右邊有六個功能按鈕,它們按照屏幕圖形顯示方式設置實現的步驟自上而下排列,程序開始運行時,除第一個按鈕“顯示設備的枚舉”是可用的,其它按鈕均不可用。由于用戶必需按照固定的步驟操作,所以,當一個按鈕任務完成后,dx1程序會將下一步任務的


圖2.1 dx1 屏幕顯示方式設置程序運行界面

按鈕設為可用。

按下“顯示設備枚舉”按鈕后,窗口左上方“運行狀態”對應的文本框中將顯示任務完成情況,若成功則顯示“Enumerate devices OK!”,否則顯示“Enumerate devices failed!” ,同時在狀態組中的設備枚舉下拉框中可以看到枚舉的設備(一般系統只有一個”主顯示設備—Display);確定設備枚舉選擇為“主顯示設備”后,可以進行“創建DirectDraw對象”、“獲得COM的IDIRECT2接口”、“設置協作級別”,每個步驟的運行狀態都會顯示在“運行狀態”右邊的文本框中;在執行了“DDraw2顯示模式的枚舉”后,狀態組下方“顯示模式DDraw2”下拉框中將列出所有顯示設備支持的顯示方式,選擇需要的圖形顯示方式,再按“設置DDraw2”的顯示方式,屏幕就會馬上切換為指定的顯示方式。

2.2.2 dx1編程實現

啟動C++ Builder后在窗口Form1中設計如圖2.1的操作界面,各對象相關屬性設置如表2.1:

控件對象類型  控件對象名稱   相關屬性      屬性值
TForm         Form1          Caption       DirectX 練習程序1
TLabel        Label1         Caption       運行狀態:
TLabel        Label2         Caption       設備的枚舉
Tlabel        Label3         Caption       顯示模式DDraw2
TEdit         Edit1          Text          (空)
                             ReadOnly      true
TGroupBox     GroupBox1      Caption       狀態
TCombBox      ComboBox1      Text          (空)
TCombBox      ComboBox2      Text          (空)
TGroupBox     GroupBox2      Caption       協作級別
TCheckBox     CheckBox1      Caption       DDSCL_ALLOWMODEX
TCheckBox     CheckBox2      Caption       DDSCL_ALLOWREBOOT
TCheckBox     CheckBox3      Caption       DDSCL_EXCLUSIVE
                             Checked       true           
TCheckBox     CheckBox4      Caption       DDSCL_FULLSCREEN
                             Checked       true
TCheckBox     CheckBox5      Caption       DDSCL_NORMAL
TCheckBox     CheckBox6      Caption       DDSCL_NOWINDOWCHANGES
                             Checked       true
TButton       Button1        Caption       設備的枚舉
TButton       Button2        Caption       創建DirectDraw對象
                             Enabled       false
TButton       Button3        Caption       獲得COM的IDIRECT2接口
                             Enabled       false
TButton       Button4        Caption       設置協作級別
                             Enabled       false
TButton       Button5        Caption       DDraw2顯示模式的枚舉
                             Enabled       false
TButton       Button6        Caption       設置DDraw2的顯示方式
                             Enabled       false

表2.1 dx1控件對象屬性設置一覽表

確定已安裝了DirectX5以上的SDK,且在C++Builder中已經將PRoject/Options/中標簽頁“Directories/Conditionals”上的“Include Path”和“Library Path”添加了DirectX5或以上SDK的路徑。

在窗口模塊中包含 #include "ddraw.h" 頭文件。

現在可以開始編寫代碼了,我們按照按鈕的順序逐個實現每個步驟的任務。

2.2.2.1 設備的枚舉

DirectDraw提供了一個函數DirectDrawEnumerate 來實現設備枚舉功能,此函數的調用格式為:

HRESULT DirectDrawEnumerate (LPDDENUMCALLBACK lpcallback LPVOID lpContext)

(1)參數lpcallback是一個回調函數的地址指針。所謂回調函數是程序員自己編寫的函數,當枚舉函數每枚舉一個設備時就調用這個回調函數一次,并把當前枚舉的設備有關信息通過參數傳遞給回調函數處理。

在dx1程序中,回調函數命名為EnumDeviceCallBack,負責將每次枚舉出的設備的描述和名稱加入到ComboBox1的列表中去,并把設備標識地址指針保存到一個lpDevices數組中以便創建DirectDraw對象時使用。

(2)參數lpContext是一用戶定義的上下文變量,我們僅取值NULL就可以了。

(3)DirectDrawEnumerate為回調函數指針,該函數的格式為:

BOOL WINAPI EnumDeviceCallBack (GUID FAR *lpGUID,

LPSTR lpDevice,

LPSTR lpDeviceName,

LPVOID lpContex)

其中:參數lpGUID 為當前枚舉設備標識地址指針;參數lpDevice 為設備描述的地址指針;參數lpDeviceName 為設備名稱的地址指針;參數 lpContext 為上下文變量地址指針,這里我們不使用它。在dx1程序中,此回調函數負責將所枚舉設備的名稱和描述顯示在ComboBox1中,并將設備標識地址保存到lpDevices數組中。為了簡化程序,這里的lpDevices數組只采用了靜態數組,最多答應保存10個元素。后面在保存顯示模式枚舉信息時使用的DisplayModes數組也是為了簡化程序,在實際編程時可以考慮動態分配。 需要說明的是,回調函數應該是一個獨立的函數,不要把它們聲明為窗口類的成員函數(否則回調不能進行),而只要聲明為普通函數就可以了。

2.2.2.2 創建DirectDraw對象

在進行DirectDraw編程之前,必需首先用DirectDrawCreate函數創建DirectDraw對象,并獲得該對象的入口指針。該函數格式如下:

HRESULT DirectDrawCreate(GUID FAR *lpDD,

LPDIRECTDRAW FAR &lplpDD,

Iunknown FAR *p)

(1)參數lpDD為指定的設備標識指針(為NULL時是主設備),在dx示例程序中的第一個按鈕“設備的枚舉”采用靜態數組保存枚舉設備的標識指針,在第二個按鈕創建DirectDraw對象時,可根據用戶在ComboBox1中的選擇,提供一個設備標識指針,以便對該設備創建DirectDraw對象。

(2)參數 lplpDD 為對象創建成功后的獲得IditrctDraw接口指針。

(3)參數p未使用,直接為NULL。

2.2.2.3 獲得COM的IDIRECT2接口

由于DirectX采用了對象組件模型COM技術(這里不再介紹),因此假如我們需要使用DirectX5或以上版本提供的功能,就需要獲得更高的IDirectDraw接口,例如:假如我們使用DirectX5開發包,就需要獲得IDirectDraw2接口。

可以利用HRESULT IdirectDraw::QueryInterface方法獲得高版本接口:

lpDD->QueryInterface(IID_IDirectDraw2,

(LPVOID *)LPDIRECTDRAW2 &lpDD2)

參數IID_IDirectDraw2是一個常量。
lpDD2是為獲得的IdDrectDraw2接口指針。
 

假如您需要使用更高版本的開發包,也可以用此方法獲得IDirectDraw3或更高的接口。高版本接口獲得后,就可以釋放低版本的接口了,方法是:lpDD->Release();

2.2.2.4 設置協作級別

玩過DirectX游戲的朋友可能都領略過“全屏獨占”和“窗口”兩種圖形模式,這就可以稱為不同的協作級別,它控制應用程序與系統及其它應用程序的交互程度,因此我們必需用HRESULT IDIRECTDRAW2::SetCooperateLevel方法設置應用程序的協作級別。

LpDD2->SetCooperateLevel(HWND handle,DWord dwFlag)

(1)參數handle是當前應用程序窗口的句柄,在C++Builder中,TForm類的Handle屬性就是當前應用程序窗口的句柄。

(2)參數dwFlag是協作標志,可以為表2.2中定義之一或多個之和。

序號        標志                        說明
(1)  DDSCL_ALLOWMODEX       答應使用Mode X模式。必須與(3)、(4)組合使用
(2)  DDSCL_ALLOWREBOOT      當使用(3)、(4)時答應用戶進行熱啟動
(3)  DDSCL_EXCLUSIVE        使用獨占方式,與(4)一起使用
(4)  DDSCL_FULLSCREEN       全屏方式,與(3)一起使用
(5)  DDSCL_NORMAL           以普通應用程序窗口方式運行
(6)  DDSCL_NOWINDOWCHANGES  DirectDraw不能自動最小化或恢復窗口


表2.2 dwFlag標志定義

在我們的dx1示例程序中,默認設置為:

DDSCL_EXCLUSIVEDDSCL_FULLSCREENDDSCL_NOWINDOWCHANGES

2.2.2.5 DDraw2顯示模式的枚舉

利用HRESULT IDIRECTDRAW2::EnumDisplayModes方法及其相應的回調函數可以列出系統顯示設備所支持的顯示方式。您開發的應用程序可以判定當前運行的計算機是否支持所需的顯示方式,也可以提供用戶選擇顯示方式的功能。

lpDD2->EnumDisplayModes(DWORD dwFlag,

LPDDSURFACEDESC lpDDSurfaceDesc,

LPVOID lpContext,

LPDDENUMMODESCALLBACK EnumDisplayModesCallBack

(1)參數dwFlag是標志參數,可以為DDEDM_REFRESHRATES(枚舉不同刷新頻率的刷新模式)和DDEDM_STANDARDVGAMODES(枚舉模式中包含Mode13)兩者之一或之和,在dx1程序中采用了后者。

(2)參數lpDDSurfaceDesc是一個過濾顯示模式的結構,只要設置為NULL就可以獲得全部顯示模式的枚舉,否則只獲得滿足指定模式的枚舉。

LPDDSURFACEDESC是一個結構,其中包含了顯示模式有關信息,主要有:

屏幕點陣 DWORD dwWidth、DWORD dwHeight;

色彩深度 DWORD ddpfPixelFormat.dwRGBBitCount

屏幕刷新頻率 DWORD dwRefreshRate

(3)參數lpContex為用戶上下文變量,設為NULL就可以了。

(4)參數EnumDisplayModesCallBack為回調函數指針,該回調函數規定有如下參數格式:

BOOL WINAPI EnumDisplayModesCallBack(LPDDSURFACEDESC lpDDSurfaceDesc

LPVOID lpContext)

其中:lpDDSurfaceDesc為當前所枚舉顯示模式的信息,lpContext為用戶上下文變量。

在dx1程序中,此回調函數負責將每次回調的顯示模式信息顯示到ComboBox2中,并記錄到一個結構數組DisplayModes中。

2.2.2.6 設置DDraw2的顯示方式

每當用戶選擇了一個顯示模式并點擊“設置DDraw2的顯示方式”按鈕后,dx1將使用RESULT IdirectDraw2::SetDisplayMode方法改變顯示方式。

lpDD2->SetDisplayModes(DWORD dwWidth,

DWORD dwHeight,

DWORD dwRGBCount,

DWORD dwRefreshRate,

DWORD dwFlags)

(1)參數dwWidth和dwHeght為顯示指定方式的點陣。

(2)參數dwRGBCount為顏色深度,如:8(256色)、16(16位色)、24(真彩色)。

(3)參數dwRefreshRate為刷新頻率,不關心時可以設置為0。

(4)參數dwFlags為使用DDSDM_STANDARDVGAMODE來設置Mode13。在dx1程序中始終設為0。

需要注重的是在IdirectDraw接口中,設置顯示模式方法不支持dwRefreshRate和dwFlags這兩個參數,所以,在有些資料中(包括C++Builder4的示例)均只介紹了DirectX3支持的IDirectDraw::SetDisplayMode(dwWidth,dwHeight,dwRGBCount)方法,請讀者注重它們的區別。

2.2.2.7 退出dx1程序需要做的事

不要忘記釋放lpDD2接口。LpDD2->Release(); 
2.2.3 dx1源程序

2.2.3.1 dx1主要文件的組成為:工程文件(dx1.bpr)、窗口文件(main.cpp)、頭文件(main.h)。

2.2.3.2 頭文件main.h

#ifndef mainH

#define mainH

//---------------------------------------------------------------------------

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

//---------------------------------------------------------------------------

class TForm1 : public TForm

{

__published: // IDE-managed Components

(略)

private: // User declarations

LPDIRECTDRAW FAR lplpDD; /* 獲得的 DirectDraw 接口指針 */

LPDIRECTDRAW2 FAR lplpDD2; /* 獲得的 DirectDraw2 接口指針 */

public: // User declarations

__fastcall TForm1(TComponent* Owner);

};

//---------------------------------------------------------------------------

extern PACKAGE TForm1 *Form1;

//---------------------------------------------------------------------------

#endif

2.2.3.3 程序文件main.cpp

#include <vcl.h>

#include "d:/tools/dx5sdk/sdk/inc/ddraw.h"

#pragma hdrstop

#include "main.h"

//---------------------------------------------------------------------------

#pragma package(smart_init)

#pragma resource "*.dfm"

TForm1 *Form1;

LPGUID FAR lpDevices[10]; /* 保存枚舉設備的標識指針 */

strUCt DisplayModes { DWORD Width,Height,Depth,Rate; } DisplayMode[100];

/* 保存顯示設備支持的顯示方式 */

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//設備枚舉回調函數---------------------------------------------------------------------------

BOOL WINAPI EnumDeviceCallBack(GUID FAR *lpGUID,LPSTR lpDevice,

LPSTR lpDeviceName,

LPVOID lpContext)

{ static char i=0;

lpDevices[i]=lpGUID;

i++;

Form1->ComboBox1->Items->Add((AnsiString)lpDevice+"--"+(AnsiString)lpDeviceName);

if(i<10)

return(DDENUMRET_OK);

else

return(DDENUMRET_CANCEL);

}

//枚舉設備---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)

{

ComboBox1->Clear();

if(FAILED(DirectDrawEnumerate(EnumDeviceCallBack,NULL)))

Edit1->Text="Enumerate Devices failed!";

else

Edit1->Text="Enumerate Devices OK!";

ComboBox1->ItemIndex=0;

Button1->Enabled=false;

Button2->Enabled=true;

}

//創建DirectDraw對象---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)

{

LPGUID FAR lpD=lpDevices[ComboBox1->ItemIndex];

if(FAILED(DirectDrawCreate(lpD,&lplpDD,NULL)))

Edit1->Text="DirectDraw Create failed!";

else

{

Edit1->Text="DirectDraw Create OK!";

ComboBox1->Enabled=false;

Button2->Enabled=false;

Button3->Enabled=true;

}

}

//獲得IDirectDraw2接口---------------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)

{

if(FAILED(lplpDD->QueryInterface(IID_IDirectDraw2,(LPVOID *)&lplpDD2)))

Edit1->Text="Get IDriectDraw2 Interface Failed!";

else

{

Edit1->Text="Get IDriectDraw2 Interface OK!";

lplpDD->Release(); /* 釋放IdirectDraw接口 */

Button3->Enabled=false;

Button4->Enabled=true;

}

}

//設置協作級別---------------------------------------------------------------------------

void __fastcall TForm1::Button4Click(TObject *Sender)

{

DWORD dwFlags=0;

if(CheckBox1->Checked) dwFlags=dwFlagsDDSCL_ALLOWMODEX;

if(CheckBox2->Checked) dwFlags=dwFlagsDDSCL_ALLOWREBOOT;

if(CheckBox3->Checked) dwFlags=dwFlagsDDSCL_EXCLUSIVE;

if(CheckBox4->Checked) dwFlags=dwFlagsDDSCL_FULLSCREEN;

if(CheckBox5->Checked) dwFlags=dwFlagsDDSCL_NORMAL;

if(CheckBox6->Checked) dwFlags=dwFlagsDDSCL_NOWINDOWCHANGES;

if(FAILED(lplpDD2->SetCooperativeLevel(Handle,dwFlags)))

Edit1->Text="Set set cooperative level Failed!";

else

{

Edit1->Text="Set cooperative level OK!";

GroupBox2->Enabled=false;

Button4->Enabled=false;

Button5->Enabled=true;

}

}

//枚舉顯示模式的回調函數---------------------------------------------------------------------------

BOOL WINAPI EnumDisplayModesCallBack(LPDDSURFACEDESC lpDesc,

LPVOID lpContext)

{

static int i=0;

char buff[256];

wsprintf(buff,"%dx%dx%dx%d",

lpDesc->dwWidth,

lpDesc->dwHeight,

lpDesc->ddpfPixelFormat.dwRGBBitCount,

lpDesc->dwRefreshRate);

Form1->ComboBox2->Items->Add(buff);

DisplayMode[i].Width=lpDesc->dwWidth;

DisplayMode[i].Height=lpDesc->dwHeight;

DisplayMode[i].Depth=lpDesc->ddpfPixelFormat.dwRGBBitCount;

DisplayMode[i].Rate=lpDesc->dwRefreshRate;

i++;

if(i<100)

return(DDENUMRET_OK);

else

return(DDENUMRET_CANCEL);

}

//枚舉顯示模式---------------------------------------------------------------------------

void __fastcall TForm1::Button5Click(TObject *Sender)

{

ComboBox2->Clear();

if(FAILED(lplpDD2->EnumDisplayModes(DDEDM_STANDARDVGAMODES,

NULL,

NULL,

(LPDDENUMMODESCALLBACK)EnumDisplayModesCallBack)))

Edit1->Text="Enumerate Display Modes failed!";

else

{

Edit1->Text="Enumerate Display Modes OK!";

ComboBox2->ItemIndex=0;

Button5->Enabled=false;

Button6->Enabled=true;

}

}

//設置顯示模式---------------------------------------------------------------------------

void __fastcall TForm1::Button6Click(TObject *Sender)

{

if(ComboBox2->ItemIndex<0)

{

ShowMessage("請先在DDraw2下拉框中選擇一種顯示方式");

return;

}

if(FAILED(lplpDD2->SetDisplayMode(

DisplayMode[ComboBox2->ItemIndex].Width,

DisplayMode[ComboBox2->ItemIndex].Height,

DisplayMode[ComboBox2->ItemIndex].Depth,

DisplayMode[ComboBox2->ItemIndex].Rate,

0)))

Edit1->Text="Set DisplayMode failed!";

}

//退出dx1---------------------------------------------------------------------------

void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)

{

if(lplpDD2) lplpDD2->Release();

}
QQ病毒 騰訊QQ空間代碼專題 PPT教程專題 ADSL應用面面俱到 fireworks教程專題 計算機和網絡技術基礎知識 校園網專題 網吧技術專題

2.3 裝入并顯示圖形文件

為了簡明地說明采用DirectDraw圖形文件的顯示技術,我們以示例程序dx2介紹圖面、圖形文件裝入、圖形縮放、圖形在圖面上顯示等的初步概念和實現技術。

2.3.1 DirectDraw顯示圖形的技術

為了顯示圖象,DirectDraw必需首先擁有類似畫布(canvas)的繪圖空間,DirectDraw并不向在DOS下那樣簡單地將顯示緩存作為繪畫的對象,而是通過DirectDraw對象創建各種不同種類的“圖面”(Suerface),圖面上的內容可以被應用程序自由地拷貝、組合,生成千變萬化的圖形。

2.3.1.1圖面分以下幾種類型:

(1)主圖面(Primary圖面):即在屏幕上顯示出來的圖面,就是GDI用于繪制Windows用戶界面的圖面。每個DirectDraw對象只能有一個主圖面,主圖面的尺寸、位置和格式由系統當前的顯示模式決定,不能改動。

(2)后臺圖面(Off-screen圖面):此類圖面不能被直接看到。一般來說,后臺圖面往往用于作為游戲精靈動畫、背景圖形等部件的存儲緩沖區。后臺圖面的尺寸是可以調整的,且可以有多個后臺圖面,其大小根據實際情況調整,不要太大或太小。一種典型的例子是:有一個精靈的動畫由4張128點陣圖形組成,那么可以將后臺圖面定義為256點的方陣,將這個動畫序列存儲下來讀者可能認為可以創建一個比主圖面大的后臺圖面以便保存游戲背景,這樣可以方便地實現滾屏,但是,DirectDraw限制后臺圖面的尺寸不能比主圖面大,除非系統的顯示卡支持。能否實現大的后臺圖面我們將在以后敘述。

(3)復合圖面(Complex圖面)和翻轉鏈(Flipping Chain):這種圖面主要用于生成平滑動畫。有關技術待制作動畫時介紹。

(4)覆蓋圖面(Overlay圖面):這是一種由硬件支持的圖面,DirectDraw不能仿真。有關技術在后面介紹。

DirectDraw可以把圖面創建在顯示內存或系統內存中,而顯示內存又分為常規顯示內存和AGP加速圖形接口內存。由于顯示內存容量是有限的,所以每個圖面具體應該創建在哪部分存儲區域中應該統籌規劃,一般將使用頻繁,需要硬件加速或實現功能的圖面安排在顯示內存。假如您不指定圖面創建的位置,DirectDraw將首先在常規顯示內存創建圖面,當常規顯示內存不夠時,若系統支持AGP內存,則先使用AGP內存,最終使用系統內存。

2.3.1.2 圖形文件的裝入

圖形文件裝入到圖面并不象想象的那么簡單,因為裝入的圖形的點陣可能與、圖面的點陣不同,這就存在圖形的縮放。另外,圖形數據在內存中的移動、復制,也是需要處理的內容。對于Windows的設備無關位圖,我們可以考慮使用Windows的功能實現:

(1)采用LoadImage函數裝入圖形文件

(2)采用圖面的GetDC方法獲得圖面與GDI兼容的設備上下文

(3)采用BitBlt函數將圖形數據拷貝到圖面中

有關GDI編程請參看有關Windows編程資料,這里讀者只需要知道固定的用法就可以了。

2.3.1.3 圖面的丟失

在DirectDraw應用程序被最小化、屏幕顯示方式改變或用戶按Alt+Tab鍵切換當前應用程序時,圖面將會丟失,因此在重新回到DirectDraw應用程序中時,必需用Restore方法恢復圖面。遺憾的是,雖然圖面被恢復了,但其中圖形數據卻丟失了,需要重新繪制。

2.3.2 dx2運行過程

啟動dx2程序后,只有第一個“執行”按鈕可以使用,按下該按鈕后,系統將創建DirectDraw對象,并設置為800*600全屏幕顯示方式;按順序按下“創建主圖面”、“創建

圖2.2 dx2 裝入并顯示圖形文件程序運行界面

后臺圖面”按鈕,分別創建對應屏幕顯示的主圖面和100*100點陣的后臺圖面;按下“后臺圖面裝入圖形”按鈕,則圖形文件view.bmp被一100*100點陣裝入到后臺圖面,屏幕上看不見圖形;再按下“主圖面裝入圖形”按鈕,view.bmp以200*100點陣縮放后裝入到主圖面(屏幕)的(0,0)位置,此時圖形顯示在屏幕左上角;繼續按“拷貝后臺圖面到主圖面”,將把后臺圖面的100*100圖形顯示在屏幕的(200,0)位置,我們可以看到兩副同樣的圖形以不同的縮放比例并排顯示在屏幕左上方;按下“圖面丟失”后,屏幕被設置成640*480的顯示方式,屏幕上顯示出的圖形消失了;用“恢復丟失的圖面”按鈕重新設置顯示方式為800*600(必需恢復顯示方式,否則圖面恢復將會失敗)并恢復圖面,此時,失去的圖形在屏幕上仍然看不見;最后,按“重新顯示圖形”來重新繪制view.bmp,屏幕重新展現原有的圖形。



2.3.3 dx2程序的編程實現

2.2.2 dx1編程實現

啟動C++ Builder后在窗口Form1中設計如圖2.2的操作界面,各對象相關屬性設置如表2.3:

控件對象類型 控件對象名稱 相關屬性 屬性值
TForm Form1 Caption DirectX 練習程序1
TLabel Label1 Caption 運行狀態:
TLabel Label2 Caption 設備的枚舉
Tlabel Label3 Caption 顯示模式DDraw2
TEdit Edit1 Text (空)
ReadOnly True
TGroupBox GroupBox1 Caption 狀態
TCheckBox CheckBox6 Caption DDSCL_NOWINDOWCHANGES
Checked true
TButton Button1 Caption 執行
TButton Button2 Caption 創建主圖面
Enabled False
TButton Button3 Caption 創建后臺圖面
Enabled False
TButton Button4 Caption 后臺圖面裝入圖形
Enabled False
TButton Button5 Caption 主圖面裝入圖形
Enabled False
TButton Button6 Caption 拷貝后臺圖面到主圖面
Enabled False
TButton Button7 Caption 圖面丟失:設置640*480方式
Enabled False
TButton Button8 Caption 恢復已丟失的圖面
Enabled False
TButton Button9 Caption 重新顯示圖形
Enabled False


表2.3 dx2控件對象屬性設置一覽表

2.3.3.1 創建主圖面

用HRESULT IDirectDraw::CreateSurface來創建圖面:

lpDD2->CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc,

LPDIRECTDRAWSURFACE FAR *lpDDSurface,

Iunknown FAR *pUnkOuter)

(1)參數lpDDSurfaceDesc是一個志向DDSURFACEDESC結構的指針,DDSURFACEDESC結構的定義比較復雜,幸好一般只需要使用其中很少的一部分。結構DDSURFACEDESC的部分描述如表2.4所示:

結構成員
描述

DOWRD dwSize
DDSURFACE結構的尺寸。在使用此結構之前,此項數據必需用sizeof函數設置

DWORD dwFlags
控制標志。主要可以設置的標志為:

DDSD_CAPS、

DDSD_HEIGHT、

DDSD_WIDTH、

DDSD_BACKBUFFERCOUNT、

DDSD_PIXELFORMATDENG 等

DWORD dwHeight
圖面高度。主圖面不需要設置

DWORD dwWidth
圖面寬度。主圖面不需要設置

DDSCAPS ddsCaps
圖面能力。DDSCAPS也是一個結構,在創建圖面時需要設置其成員dwCaps的值,以便確定所建圖面的性質。

DwCaps的取值主要有:

DDSCAPS_PRIMARYSURFACE:主圖面

DDSCAPS_OFFSCREENPLAIN:后臺圖面

DDSCAPS_COMPLEX:復合圖面

DDSCAPS_FLIP:圖面翻轉鏈

DDSCAPS_OVERLAY:覆蓋圖面

DDSCAPS_VIDEOMEMORY:圖面創建在顯示內存

DDSCAPS_LOCALVIDMEM:使用常規顯示內存

DDSCAPS_NONLOCALVIDMEM:使用AGP內存

DDSCAPS_SYSTEMMEMORY:圖面創建在系統內存




表2.4 DDSURFACEDESC結構的部分成員說明

(2)參數lpDDSurface返回一個指向所創建圖面的指針。

(3)參數pUnkOuter未使用,必需為NULL。

創建主圖面需要以下步驟:



(1)獲得并設置DDSURFACEDESC結構的尺寸dwSize:ddsd.dwSize=sizeof(ddsd);

(2)簡單地設置ddsd.dwFlags=DDSD_CAPS;

(3)設置主圖面標志:ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE;

(4)調用CreateSurface方法創建圖面。



2.3.3.2 創建后臺圖面

后臺圖面的創建與創建主圖面基本相同,只是在DDDURFACEDESC結構中多給出一些信息。創建后臺圖面需要以下步驟:

(1) 獲得并設置DDSURFACEDESC結構的尺寸dwSize:ddsd.dwSize=sizeof(ddsd);

(2) 設置ddsd.dwFlags=DDSD_CAPSDDSD_HEIGHTDDSD_WIDTH;

(3) 設置后臺表面的寬和高(dx2中設為100):ddsd.dwHeight=100; ddsd.dwWidth=100;

(4) 設置后臺圖面標志:ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN;

(5)調用CreateSurface方法創建圖面。



2.3.3.3 圖形文件的裝入后臺圖面和圖形文件的裝入主圖面

圖形文件的裝入主要采用Windows的函數,雖然使用C++Builder的TCavas對象打開圖形文件要方便一些,但是在BitBlt時不夠穩定,因此dx2還是選擇了前者。

dx2在實現圖形內存數據復制時采用了GDI,在DirectDrawSurface對象中有GetDC和ReleaseDC兩個方法,以便取得HDC并調用GDI。

HRESULT IDirectDrawSurface::GetDC(HDC FAR *hdc)

HRESULT IDirectDrawSurface::ReleaseDC(HDC hdc)

參數hdc是一個設備句柄。

BitBlt雖然速度比較慢,但是兼容性好,能夠支持不同的顯示模式,而且能夠自動進行格式轉換。

2.3.3.4 后臺圖面圖形拷貝到主圖面顯示

這里同樣使用了BitBlt,將后臺圖面的數據復制到主圖面并顯示出來。

2.3.3.5 丟失圖面及恢復初始顯示方式和圖面

在dx2中我們演示了當改變屏幕顯示方式時,圖面丟失的現象,并且說明了在圖面丟失后可以用HRESULT IDirectDrawSurface::Restore()方法來恢復圖面,同時必需重新繪制圖面上的圖形。

Restore方法沒有參數,但是若要成功恢復已丟失的圖面,必需屏幕顯示方式重新恢復到其初始的狀態。

為了判定圖面是否已經丟失,也可以使用HRESULT IDirectDrawSurface::IsLost()方法來進行檢測,若返回值為DDERR_SURFACELOST則說明圖面確實丟失了。在dx2中沒有進行此判定,讀者可以根據自己的理解修改dx2,實現恢復圖面前首先進行圖面是否丟失的判定。

2.3.4 dx2源程序

2.3.4.1 dx2主要文件的組成為:工程文件(dx2.bpr)、窗口文件(main.cpp)、頭文件(main.h)、view.bmp。

2.3.4.2 頭文件main.h

#ifndef mainH

#define mainH

//---------------------------------------------------------------------------

#include <Classes.hpp>

#include <Controls.hpp>

#include <StdCtrls.hpp>

#include <Forms.hpp>

#include <Dialogs.hpp>

#include "d:/tools/dx5sdk/sdk/inc/ddraw.h"

//---------------------------------------------------------------------------

char CR[]={13,10,0};

//---------------------------------------------------------------------------

class TForm1 : public TForm

{

__published: // IDE-managed Components

TButton *Button1;

TLabel *Label1;

TGroupBox *GroupBox1;

TMemo *Memo1;

TButton *Button2;

TButton *Button3;

TButton *Button4;

TButton *Button5;

TButton *Button6;

TButton *Button7;

TButton *Button8;

TButton *Button9;

void __fastcall Button1Click(TObject *Sender);

void __fastcall Button2Click(TObject *Sender);

void __fastcall FormClose(TObject *Sender, TCloseAction &Action);

void __fastcall Button3Click(TObject *Sender);

void __fastcall Button4Click(TObject *Sender);

void __fastcall Button5Click(TObject *Sender);

void __fastcall Button6Click(TObject *Sender);

void __fastcall Button7Click(TObject *Sender);

void __fastcall Button8Click(TObject *Sender);

void __fastcall Button9Click(TObject *Sender);

private: // User declarations

LPDIRECTDRAW FAR lpDD;

LPDIRECTDRAW2 FAR lpDD2;

DDSURFACEDESC ddsd;

LPDIRECTDRAWSURFACE FAR lpDDPrimary,lpDDOffScreen;

public: // User declarations

__fastcall TForm1(TComponent* Owner);

};


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91麻豆桃色免费看| 欧美日韩在线视频观看| 日韩av黄色在线观看| 国产视频久久久久久久| 精品久久久久久| 狠狠躁夜夜躁人人躁婷婷91| 欧美一级电影免费在线观看| 欧美成人免费观看| 精品国产依人香蕉在线精品| 亚洲欧美国产精品va在线观看| 91在线看www| 91精品国产综合久久香蕉922| 亚洲精品福利免费在线观看| 国产精品免费电影| 亚洲第一免费网站| 91av免费观看91av精品在线| 欧美精品一区二区免费| 成人免费视频97| 国产欧美在线播放| 国产精品视频公开费视频| 亚洲一区二区三区毛片| 亚洲日本成人网| 91精品视频观看| 日韩精品极品在线观看播放免费视频| 97精品视频在线播放| 日韩av影视综合网| 国产成人精品a视频一区www| 国产欧美精品日韩| 日韩在线高清视频| 欧美日韩中文字幕综合视频| 日韩av在线免费看| 国产精品r级在线| 中文字幕一区日韩电影| 日韩精品在线免费观看视频| 亚洲视频在线观看免费| 亚洲国产精品va在线看黑人动漫| 欧美在线一区二区视频| 久久久久久亚洲| 伊人久久免费视频| 日韩精品在线免费观看| 成人妇女淫片aaaa视频| 国产精品午夜视频| 日韩欧美在线第一页| 精品久久香蕉国产线看观看亚洲| 国产成人激情小视频| 九九热这里只有在线精品视| 乱亲女秽乱长久久久| 亚洲夜晚福利在线观看| 欧美大片第1页| 亚洲福利视频网站| 国产精品一二三视频| 一道本无吗dⅴd在线播放一区| 综合国产在线观看| 色偷偷888欧美精品久久久| 精品国产91乱高清在线观看| 88xx成人精品| 久久久久久久影院| 亚洲国产精品资源| 亚洲国产欧美一区二区丝袜黑人| 日韩欧美在线看| 成人黄色午夜影院| 欧美成人免费在线视频| xx视频.9999.com| 日韩欧美国产骚| 亚洲iv一区二区三区| 日韩成人在线免费观看| 精品久久久久久久久久久| 日本久久中文字幕| 在线观看国产精品淫| 欧美日本啪啪无遮挡网站| 亚洲色图15p| 国内精品久久影院| 欧美日韩国产在线看| 久久久噜噜噜久久中文字免| 国产精品美女久久久久久免费| 这里只有精品在线观看| 国产精品第七十二页| 成人欧美一区二区三区在线| 国模精品视频一区二区| 97在线视频精品| 欧美在线观看一区二区三区| 最近2019年手机中文字幕| 欧美日韩精品在线播放| 日韩在线视频观看正片免费网站| 亚洲精品www| 91美女片黄在线观看游戏| 亚洲免费电影在线观看| 97精品视频在线播放| 国产日韩欧美综合| 亚洲成av人片在线观看香蕉| 岛国av午夜精品| 91福利视频在线观看| 国产精品扒开腿做爽爽爽的视频| 久久中文字幕视频| 国产一区二区三区精品久久久| 国产精品白丝av嫩草影院| 久久av在线看| 亚洲欧洲一区二区三区在线观看| 91免费综合在线| 日韩av网址在线观看| 国产精品网站入口| 亚洲三级 欧美三级| 中文字幕日本精品| 国产成人精品在线| 亚洲视频精品在线| 国模吧一区二区三区| 亚洲国产古装精品网站| 欧美国产亚洲精品久久久8v| 中文字幕精品一区久久久久| 欧美另类在线播放| 精品欧美国产一区二区三区| 国产精品久久久久久久久久久久久久| 亚洲欧美一区二区三区四区| 亚洲护士老师的毛茸茸最新章节| 国产精品视频男人的天堂| 欧美性猛交xxxx免费看漫画| 欧美午夜美女看片| 免费不卡在线观看av| 在线观看日韩专区| 色与欲影视天天看综合网| 色黄久久久久久| 欧美日韩中文字幕在线| 成人国产精品一区| 久久国产精品首页| 色婷婷综合久久久久| 久久免费视频在线观看| 欧美日韩中文字幕在线| 国产精品色午夜在线观看| 国产成人一区三区| 日韩中文视频免费在线观看| 精品国产一区二区三区久久狼黑人| 丝袜美腿精品国产二区| 久久99精品久久久久久琪琪| 亚洲综合成人婷婷小说| 国产精品wwww| 国产91在线播放| 亚洲2020天天堂在线观看| 欧美大学生性色视频| 欧美午夜激情在线| 欧美一级淫片videoshd| 午夜精品一区二区三区视频免费看| 九九视频直播综合网| 亚洲伊人久久大香线蕉av| 中文字幕不卡在线视频极品| 综合国产在线视频| 欧美日韩电影在线观看| 亚洲第一色在线| 亚洲偷欧美偷国内偷| 久久精品视频亚洲| 久久久中精品2020中文| 国产情人节一区| 揄拍成人国产精品视频| 美女久久久久久久| 国产精品中文在线| 欧美激情综合色综合啪啪五月| 亚洲精品美女网站| 中文字幕精品久久| 国产情人节一区| 国产成人精品免费视频| 色综合色综合久久综合频道88| 成人激情电影一区二区| 国产精品美女久久| 中文字幕精品视频| 欧美人成在线视频|