国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

DirectX游戲開發(fā)入門

2019-11-17 05:02:00
字體:
來源:轉載
供稿:網(wǎng)友
一.簡介 今天我們要接觸到令人敬畏的DirectX。它比Windows GDI要快好幾倍,可用于不同的語言和多種平臺,支持從繪制象素到高級3D圖象,從播放簡單聲音到數(shù)字音樂,從鍵盤控制到反震手柄……它給你游戲編程所需的一切(有點夸張)。         當然了,它是巨大的,需要好幾本書才能含蓋它的全部。先不要去擔心我在這里所教給你之外的數(shù)不清的知識,究竟我把你推到了起跑線上。  閱讀本章,你需要前幾章的知識和C語言的知識,由于我們還要談到組件對象模型(COM),它是面向對象系統(tǒng)的基礎,你最好還要有一點兒C++的知識。沒有也不太要緊,我在講到這處時會照顧你的。反正你記住,使用DirectX并不需要多少C++的知識。開始吧! 二.什么是DirectX?  DirectX是游戲制作者的API(application Development Interface)。它是一組答應你直接控制計算機硬件設備的軟件。假如你的硬件支持DirectX,并且你用硬件加速你的程序,這就意味著一個字——快。不用擔心你的硬件知識,你不會真正的接觸到它們。我們是通過硬件抽象層(HAL)和硬件仿真層(HEL)來保證設備無關性和讓你的程序正常運行。  DirectX由很多組件構成,每一個都有特定的用途。組件DirectDraw是最為重要的一個,因為所有的圖形都要用到它,它是2D圖形的引擎,3D圖形也同樣離不開它。DirectDraw是我們今天就要說的。其它的組件是:  1.DirectSound:提供硬件和軟件的聲音混合與回放。  2.DirectMusic:處理基于消息的音樂數(shù)據(jù)。它支持樂器數(shù)字接口(MIDI)并為創(chuàng)建交互式音樂提供創(chuàng)作工具。  3.DirectPlay:使得通過調制解調器鏈接或通過網(wǎng)絡來與應用程序相連成為可能。  4.Direct3D:是一個三維圖形包,它提供一個高級的保留模式(Retained Mode)接口,這使得你能夠實現(xiàn)一個完整的三維圖形系統(tǒng)。它還包含一個低級的即時模式(Immediate Mode)接口,使得應用程序獲得對渲染管線的完全控制。  5.DirectInput:為包括游戲桿、鼠標、鍵盤和游戲控制器在內的輸入設備提供支持。它還為反饋游戲設備提供支持。  6.DirectSetup:為DirectX提供了一個簡單的安裝過程。它簡化了更新顯示和音頻驅動程序的過程,并且確保沒有硬件或軟件沖突的存在。  7.AutoPlay:讓你能夠制作一張一旦插入驅動器就能自動安裝的光盤。AutoPlay并非DirectX所獨有,因為它是Microsoft Win32 API的一部分。  組件對象模型(COM)是DirectX的基礎,有一些技巧建立COM對象——別問我怎么做——但你知道一點點還是有好處的。我只是簡單說一下,假如你有愛好,具體的細節(jié)就自己查資料吧!可能下一節(jié)你有些困惑,但不要緊,我所說的你不用太明白,究竟我們的目的是使用COM對象,這可比創(chuàng)建輕易多了。三.組件對象模型(COM)  COM接口是DirectX技術的基礎,沒有COM就沒有DirectX。(不用擔心,你只需要對COM技術有一個粗淺的了解就可以使用DirectX——只要你在編寫DirectX應用程序時遵循一定的步驟,甚至都可以在不了解COM的情況下使用DirectX。  DirectX的大多數(shù)API都是基于COM結構的。COM為軟件模塊化和軟件重用提供了最堅實的基礎,它的最重要的概念就是接口(interface),接口是軟件重用的最基本方法。更專業(yè)的說,接口是一系列操作的規(guī)范描述,即接口規(guī)范。  所有的COM接口都是從Iunknown接口繼續(xù)而來的,IUnknown接口是所有COM接口的根。IUnknown接口具有3個方法:  · QueryInterface():此方法查詢新接口,并在新接口存在時返回之。  · AddRef():此方法在接口或其它應用程序連編到此COM對象上時將引用計數(shù)值遞加1。  · Release():此方法將COM對象的引用計數(shù)遞減1。當引用計數(shù)遞減到0時,該COM對象自動釋放。  所有COM對象都具有這三個方法。雖然DirectX應用程序一般不需要考慮引用計數(shù)的問題,但引用計數(shù)確實是存在的,它已經(jīng)由DirectX自動完成了。我們所要做的,就是創(chuàng)建DirectX對象,然后在使用完畢后調用Release方法釋放引用。 更多內容請看J2ME游戲開發(fā)應用  Solaris基礎知識入門  Wlan組網(wǎng)----家庭專題專題,或
四.設置  用DirectX創(chuàng)建程序,你需要有三件主要的事要做。第一件事是COM對象本身,它們包含在.DLL文件里,這些.DLL文件需要在Windows里注冊,這在安裝DirectX軟件包時已經(jīng)完成了。這些對象是我們創(chuàng)建DirectX應用程序時用到的接口,例如IdirectDraw。         但這還不夠,因為在COM層上直接使用DirectX是令人沮喪的和乏味的。我們希望有更輕易的辦法解決它。利用靜態(tài)庫(.LIB文件)是個好辦法,它是DirectX軟件包的一部分,你可以從Microsoft免費獲得。它有一個“打包”函數(shù)使你工作更輕松。使用DirectX的不同組件,你需要鏈接不同的靜態(tài)庫。例如你要使用DirectDraw組件,你就需要ddraw.lib。  最后,你還需要DrectX頭文件,它包含函數(shù)原形、宏、常量和你需要用到的各種類型。對于DirectDraw,這個頭文件是ddraw.h。

要確認你使用了正確的文件版本,你還得讓編譯器包含軟件開發(fā)包的目錄。具體的做法是:  首先點擊Tool菜單,選擇Options,然后點擊Directories,在Show Directories for 組合框下拉菜單中選擇Include files,增加一個新的目錄。將你的DirectX的路徑填入。(例如:C:DXSDKinclude)然后將它移到列表的第一位,使編譯時第一個尋找它(防止尋找老版本)。然后選擇Show Directories for組合框下拉菜單中的Library files,方法同前,只是把include改成lib。現(xiàn)在,你已經(jīng)設置完了DirectX。你仍然需要手動增加一些庫文件到你的項目中,但先不急,我將在以后講它。我們將使用DirectX 7.0。五.DirectX版本號  你可能認為版本號沒有什么好講的,但我們確實要說一說。Microsoft在DirectX里創(chuàng)建了令人難以置信的科技,但它并不代表不使人迷惑。對于每一個DirectX版本,并不是所有的接口都一次次的升級。因此,盡管DirectX有了7個版本(我寫文章時DirectX8.0正預備發(fā)布),但DirectDraw并沒有7個版本。當DirectX6是最新版本時,DirectDraw的最新接口版本是IDirectDraw4,不是IDirectDraw6。現(xiàn)在最新的版本是DirectX7,所以我們要用IDrectDraw7。很希奇,是不是?我想你已經(jīng)明白了我的意思,請不用因為以后看到的感到困惑了。  最后一件事。當我寫這篇文章時,DirectX7是最新的可用版本,但或許現(xiàn)在你已經(jīng)有了DirectX8,并且或許你還聽說了,DirectDraw將不再升級了,取代它的是DirectX Graphics,這是一個功能強大的圖形API。但DirectDraw不升級就意味著我們不學習它了,究竟都離不開COM。假如你想用DirectX8的接口寫2D的游戲,你需要用3D方法去創(chuàng)建2D觀點。聽起來很棒,是的,的確如此,因為使用3D接口將給你更多的硬件支持,例如阿爾發(fā)混合。但這也恰恰是個問題,假如機器沒有相應的硬件設備,程序會以更慢的速度運行。  DirectDraw是很輕易學的。由于DirectX中的3D圖形是基于DirectDraw的,3D應用程序在DirectDraw環(huán)境中執(zhí)行;極少有應用程序專門使用3D。大多數(shù)程序使用3D函數(shù)對一些對象建模,而另一些對象,諸如背景和精靈,是以2D圖形渲染的。所以本系列將使用DirectDraw。關于DirectX8,我還沒有太多的了解,因此我只能對DirecX7做具體介紹。總的來說,你使用DirectX,還是離不開DirectDraw的。六.DirectDraw概述  在你的程序中使用DirectDraw,你至少要做四件事,它們是:  1、建立一個DirectDraw對象。  2、設置協(xié)作等級。  3、設置顯示模式和色彩深度(全屏模式)。  4、至少創(chuàng)建一個DirectDraw表面。  在講怎樣完成以上步驟之前,先讓我們了解一下每一步的含義。第一個,要創(chuàng)建一個DirectDraw對象,這意味著我們要建立一個指向IDirectDraw7接口的指針。這很簡單,不是嗎?有三種辦法可以實現(xiàn)它,你可以直接使用COM,或使用DirectDraw的兩個函數(shù)之一。三種辦法各有千秋,我們過一會兒將具體介紹。第二個,設置操作等級。這可能對你來說比較新鮮。協(xié)作是由于Windows是一個多任務操作系統(tǒng)而產(chǎn)生的概念。意思是所有運行的程序都要隨時告知Windows它們將要或正在使用的資源,這將保證你所要使用的資源不會被windows再分配給別的應用程序。不用擔心,有一個很簡單的函數(shù)完成它。  第三個你是否有點熟悉?假如你要寫一個全屏的程序,通常是游戲程序,你需要設置顯示模式和色彩深度。在Windows的應用程序里做這些通常不是一個好主意,因為它能導致其它程序的同時運行出現(xiàn)問題。當你結束自己的程序時,你當然要恢復到改變前的狀態(tài)。設置全屏模式,只是調用一個單獨的DirectDraw的函數(shù),程序結束后,要恢復原來的狀態(tài)。  最后,也是最重要的,是DirectDraw表面的概念。操縱表面是DirectDraw的全部。簡單的說,DirectDraw表面是一個用于存儲圖象數(shù)據(jù)的線性內存區(qū)域。DirectDraw表面的大小就是以象素為單位,用寬和高來定義。所以你可以認為表面是一個用來畫圖的矩形區(qū)域。它有自己的接口,稱作IDirectDrawSurface7。有三種主要的表面,我們將在本章和下一章分別用到它們。  · 主表面:每一個DirectDraw應用程序都有一個主表面。主表面就相當于用戶的顯示器。它的內容是可見的。同理,主表面就是根據(jù)顯示器的顯示模式設定寬和高。  · 后緩沖區(qū):后緩沖區(qū)是緊隨主表面的表面,但它不可見。它是動畫沒有閃爍的主因,通常,你在后緩沖區(qū)畫好每一幀,然后把后緩沖區(qū)的內容拷貝到主表面,使它顯示出來。由于它緊隨著主表面,所以它的大小同主表面相同。(你就理解為樓上和樓下的關系)  · 離屏緩沖區(qū):它很象后緩沖區(qū),只是它不是緊挨著主表面。盡管你可以用它作任何事,但它經(jīng)常被用來存儲位圖。離屏緩沖區(qū)你可以任意設置大小,唯一的限制是你內存的大小。  DirectDraw表面可以在系統(tǒng)內存中建立,或直接建立在顯示內存中。假如你都建立在顯示內存中,速度效果將是最好的,如在系統(tǒng)內存就要慢一些了。假如你把一個表面存儲在顯示內存中,另一個在系統(tǒng)內存中,性能會有一些損失的,尤其是顯示卡與主板之間有一個令人惡心的帶寬。總之,假如能把表面都建立在顯示內存中,你或許應該盡力做到。  OK,我們總算有了一點兒認知,讓我們看看具體怎么做吧!這兒有一個計劃,我們將建立一個全屏模式下,16位色彩,640×480分辨率的程序,我將告訴你全部你需要做的。但開始前,你需要對Windows編程有一點了解。想必你看過了前面幾章,應該對創(chuàng)建窗口已經(jīng)熟悉了。由于這是一個全屏的程序,你不需要任何地窗口控制,所以你的窗口風格應該用WS_POUPWS_VISIBLE。弄好了嗎?All right,出發(fā)吧! 更多內容請看J2ME游戲開發(fā)應用  Solaris基礎知識入門  Wlan組網(wǎng)----家庭專題專題,或

七.建立DIRECTDRAW對象   
      象我前面說過的,有三種方法。我們可以用兩個DIRECTDRAW函數(shù)中的任何一個,或者直接調用COM對象。讓我們每一個都試試,使我們自己熟悉它們。我將告訴你的最后一個方法可能是目前為止最簡單的,可能你會喜歡用它。至于另外兩個,打眼兒一看,你會覺得有些希奇。首先,看看DirectDrawCreate():
HRESULT WINAPI DirectDrawCreate(
GUID FAR *lpGUID,
LPDIRECTDRAW FAR *lplpDD,
IUnknown FAR *pUnkOuter
);    看起來是不是有點兒復雜?HRESULT返回的類型是DirectDraw函數(shù)的標準。假如成功,返回值是DD_OK。假如失敗,函數(shù)將返回一個錯誤常量,有幾個錯誤常量供選擇,但我不想細講,更不想列出這些常量,反正你可以通過幫助文件隨時查閱它們。但有一件事兒我得告訴你,有兩個非常有用的宏可以幫助你知道函數(shù)調用成功與否:SUCCEEDED()和FAILED()。從字面上你就知道它們的分工了,是不是?只要把函數(shù)放到宏里面,你就知道結果了。無論如何,我們還得看看函數(shù)的參數(shù):  · GUID FAR *lpGUID:是一個全局唯一標識符(GUID)的地址,代表將要創(chuàng)建的驅動程序。假如該參數(shù)是NULL,那么該調用指向當前的顯示驅動程序。新版本的DirectDraw答應向該參數(shù)傳遞下列兩種標志之一,以控制當前顯示的行為:   DDCREATE_EMULATIONONLY:DirectDraw只使用仿真(HEL),不使用硬件支持特性。   DDCREATE_HARDWAREONLY:DirectDraw對象不使用仿真特性。只能使用硬件抽象層(HAL),假如硬件不能支持應用程序,將不再尋求硬件仿真層(HEL)的支持而返回錯誤信號。  · LPDIRECTDRAW FAR *lplpDD:表示假如調用成功則返回有效的DirectDraw對象指針的地址,它是DirectDraw對象指針的指針(“DD”表示DirectDraw,“l(fā)p”表示32位長指針,“l(fā)plp”表示長指針的長指針)。應用程序一般需要使用此指針的地址(即DirectDraw對象指針)初始化DirectDraw對象。  · IUnknown FAR *pUnkOuter:這是為高級COM應用保留的參數(shù),設置為NULL好了。  不要被我羅里羅嗦的解釋嚇倒,實際應用起來很簡單,解釋這么多,不過是為了讓你明白根本道理。現(xiàn)在有一個問題,這個函數(shù)給你一個指向IDirectDraw接口的指針,但我們想要一個指向IDirectDraw7接口的指針,我們應該怎么做呢?一旦DirectDraw應用程序通過DirectDrawCreate()函數(shù)獲得了指向DirectDraw對象的指針,COM就有一種機制可以用來查看該對象是否支持其它接口。IUnknown的QueryInterface()方法使得你能夠確定一個對象是否支持一個特定的接口:
HRESULT QueryInterface(
 REFIID iid, // Identifier of the requested interface
 void **ppvObject // Address of output variable that receives the
);
  第一個參數(shù)是一個要查詢的對象的引用標識符。對于IDirectDraw7來說就是IID_IDirectDraw7。使用它,你必須把dxguid.lib鏈接入你的項目中;第二個參數(shù)是一個變量的地址,我們應該在程序的頭部先聲明一個LPDIRECTDRAW7類型的指針,再把指針的地址傳遞給這個參數(shù)。假如你使用的是Visual C++6.0,你在這兒或許還需要一個類型強制符。假如機器支持你指定的接口,函數(shù)將返回一個指向該接口的指針。通過該指針,代碼就獲得對新接口的方法的訪問。假如函數(shù)調用成功,返回值是S_OK。  現(xiàn)在我們有了兩個接口指針:一個是IDirectDraw接口,另一個是IDirectDraw7。后一個是我們想要的;前一個就沒有用了。我們注重,在代碼中每當找到一個新的有效對象時,前一個對象就通過Release()函數(shù)被釋放掉。這個函數(shù)很簡單:ULONG Release(void);
  返回的值是一個參考數(shù)字,只有在程序測試和調試時才用得著這個數(shù)字。為了安全起見,你還應該把釋放了的指針賦值為NULL。我們也通常在聲明這樣的指針時設置它為NULL。你跟上我的節(jié)奏了嗎?可能要記憶的東西太多了,但是你不得不記憶。讓我們把談到的這些做個實例吧,實例的目的是得到IDirectDraw7接口的指針:LPDIRECTDRAW lpdd = NULL; // pointer to IDirectDraw (temporary)
LPDIRECTDRAW7 lpdd7 = NULL; // pointer to IDirectDraw7 (what we want)// get the IDirectDraw interface pointer
if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL)))
{
 // error-handling code here
}// query for IDirectDraw7 pointer
if (FAILED(lpdd->QueryInterface(IID_IDirectDraw7, (void**)&lpdd7)))
{
 // error-handling code here
}
else
{
 // success! release IDirectDraw since we don t need it anymore

 lpdd->Release();
 lpdd = NULL;
}
  現(xiàn)在,假如你是一個C程序員,你可能被調用QueryInterface()和Release()這兩個函數(shù)的方法弄得有點模糊。你以前可能看過“->”這個符號,在C語言的結構部分,當結構聲明了一個指針變量,調用結構成員時,就用“結構指針名->結構成員”,同樣的道理,只是這里把結構成員換成了函數(shù)。既然說到這個話題,我就介紹一下另一個C++符號,范圍定義符號“::”,它是表示從屬關系的符號,舉個例子你就明白了:比如QueryInterface()函數(shù)是屬于IUnknown類的,就可以表示為IUnknown::QueryInterface()。我們將來會經(jīng)常用到這個符號的,所以記住它。  說實在的,以上的主要目的是為了演示怎樣使用QueryInterface()方法,它是所有DirectX接口的一部分,所以讓我們往下進行。我們將直接使用COM方法獲得接口指針。這種方法的好處是你可以立即獲得IDirectDraw7接口指針,不用象剛才那么麻煩。首先,你必須得初始化COM,象這樣:HRESULT CoInitialize(LPVOID pvReserved);
  不能在輕易了,你必須把參數(shù)設置為NULL。當你結束COM調用,你需要拋棄它,也很簡單:void CoUninitialize(void);
  我通常在DirecX程序的一開始就調用CoInitialize()函數(shù),在程序的最末端,當我釋放了所有的DirectX對象后,使用CoUninitialize()。一旦你初始化了COM,你就可以用CoCreateInterface()函數(shù)得到你想要的指針,它看起來有點丑陋:STDAPI CoCreateInstance(
 REFCLSID rclsid, // Class identifier (CLSID) of the object
 LPUNKNOWN pUnkOuter, // Pointer to whether object is or isn t part
 // of an aggregate
 DWord dwClsContext, // Context for running executable code
 REFIID riid, // Reference to the identifier of the interface
 LPVOID *ppv // Address of output variable that receives
); // the interface pointer requested in riid
  假如成功,返回值是S_OK。參數(shù)需要好好解釋一下,看下面:  · REFCLSID rclsid:這是一個類標識符(不要同GUID搞混了哦),有為它預備好的常量標識符供你選擇。對于IDirectDraw7來說,使用CLSID_DirectDraw。注重沒有版本號,因為它是類標識符,不是接口標識符。  · LPUNKNOWN pUnkOuter:這個同我們在DirectDrawCreate()中看到的一樣,設置為NULL。  · DWORD dwClsContext:這個必需的值叫作執(zhí)行上下文,它定義了控制新生成對象的代碼將要執(zhí)行的方式。這個值可以從CLSCTX列表中選取,對于我們現(xiàn)在的情況,我們用CLSCTX_ALL,它包含了所有可能的值。  · REIID riid:我們在QueryInterface()中看過它。這個IID是IID_DirectDraw7。  · LPVOID *ppv:依然同DirectDrawCreate()中的一樣,是指向接口指針的地址。  調用這個函數(shù)將取代我們上一個方法中的DirectDrawCreate()、QueryInterface()和Release()三個函數(shù),所以簡捷一些。當然,使用哪種隨便你了。直接調用COM比我們先前用的方法少了一個多于地接口指針。一旦你用CoCreateInstance()建立了一個對象,你還得調用Initialize()函數(shù)初始化這個對象。在C++里可能寫成這樣IDirectDraw7::Initialize()。以下是它的原形:HRESULT Initialize(GUID FAR *lpGUID);
  將使用同DirectDrawCreate()中一樣的GUID,就是NULL。在我們繼續(xù)前,讓我給你看一個使用COM創(chuàng)建DirectDraw對象的例子:LPDIRECTDRAW7 lpdd7; // interface pointer// initialize COM
CoInitialize(NULL);// create the object
CoCreateInstance(CLSID_DirectDraw, NULL, CLSCTX_ALL, IID_IDirectDraw7, (void**)&lpdd7);// initialize the object
lpdd7->Initialize(NULL);
  直接看例子可能使你更輕易理解一些。好了,建立DirectDraw對象的最難的兩種方法你已經(jīng)學會了,那就讓我們看看最簡單的方法吧! 它只有一步,沒有多于的接口指針,不用設置COM,什么都沒有。就是下面這個函數(shù):DirectDrawCreateEx(
 GUID FAR *lpGuid,
 LPVOID *lplpDD,
 REFIID iid,
 IUnknown FAR *pUnkOuter
);
  所有的參數(shù)我們看起來都比較熟悉,因為我們剛才看過它們了。第一個,第二個和第四個參數(shù)同DirectDrawCreate()中的一樣,只是這里需要用(void**)來修飾一下我們接口指針的地址——別問我為什么,這不是我的主意。第三個參數(shù),riid,是我們在函數(shù)CoCreateInstance()中傳遞的接口ID,所以我們就用IID_IDirectDraw7。就這樣,無論用哪種方法,我們得到了我們的DirectDraw對象,我們可以繼續(xù)使用這個對象了。要做的頭兩件事是設置協(xié)作等級和顯示協(xié)議。
八.作等級和顯示模式  我不需要說太多。Windows編程設置協(xié)作級別你只需要調用IDirectDraw7::SetCoOperativeLevel()函數(shù);設置顯示模式你就調用IDirectDraw7::SetDisplayMode()函數(shù)。就這么簡單!先來看看協(xié)作級別。這就是函數(shù)原形:

   
   
HRESULT SetCooperativeLevel(
 HWND hWnd,
 DWORD dwFlags
);
  返回的類型是HRESULT,你應該已經(jīng)熟悉它了。對于所有的DirectX函數(shù)調用,你都可以用SUCCEEDED()和FAILED()宏檢測調用的結果。以下是函數(shù)SetCooperativeLevel()的參數(shù):  · HWND hWnd:很熟悉吧!傳遞主窗口的句柄給它,使Windows知道誰將使用它的資源。   · DWORD dwFlags:這個也很眼熟吧!每次我們看到dwFlags參數(shù),幾乎都有一個大的標志常量列表供我們選擇,并且可以用“”組合。這次也不會讓你失望的哦!   1.SCL_ALLOWMODEX:啟用Mode X 顯示模式(如320×200,320×240或者320×400)。該標志只能用于DDSCL_EXCLUSIVE和DDSCL_FULLSCREEN模式。   2.SCL_ALLOWREBOOT:在獨占模式中啟用Ctrl+Alt+Del組合鍵功能。   3.SCL_EXCLUSIVE:請求獨占模式,必須與DDSCL_FULLSCREEN同時使用。   4.SCL_FULLSCREEN:獨占模式的擁有者負責整個主表面,GDI被忽略,必須與DDSCL_EXCLUSIVE同時使用。   5.SCL_NORMAL:表示常規(guī)的Windows應用程序,不能與DDSCL_ALLOWMODEX、DDSCL_EXCLUSEIVE或DDSCL_FULLSCREEN標志同時使用,在該模式下運行的應用程序不能進行頁交換或者更改主調色板。   6.SCL_NOWINDOWCHANGES:防止DirectDraw最小化或恢復應用程序窗口。
 
  還有幾個標志常量我們暫時用不到,就不說了。由于我們要建立一個全屏的640×480×16的顯示模式,所以我們得這樣設置:lpdd7->ooperativeLevel(hwnd, DDSCL_ALLOWREBOOT DDSCL_EXCLUSIVE DDSCL_FULLSCREEN);
  現(xiàn)在協(xié)作級別已經(jīng)設置好了,讓我們再看看改變顯示模式的函數(shù):HRESULT SetDisplayMode(
DWORD dwWidth,
DWORD dwHeight,
DWORD dwBPP,
DWORD dwRefreshRate,
DWORD dwFlags
);   別忘了用宏去檢測調用函數(shù)的成功或失敗!大多數(shù)的參數(shù)同你料想的差不多:  · DWORD dwWidth,dwHeight:以象素為單位,新顯示模式的尺寸。  · DWORD dwBPP:新顯示模式的色彩深度。就是每一個象素有多少位字節(jié)。可以設置為8,16,24或32。警告:很多顯示卡不支持24-bits。  · DWORD dwRefreshRate:屏幕的刷新頻率。但你最好設置為0,使用默認的刷新頻率。  · DWORD dwFlags:對不起,這次沒有列表了^_^,唯一的選擇是DDSDM_STANDARDVGAMODE,它把顯示模式設置為0x13(DOS程序員的好朋友),取代了Mode X的320×200×8的模式。假如你還想使用其它的模式(你可能經(jīng)常需要),沒有問題,把它設置為0好了。  這些就是顯示模式的設置,事先最好了解你的顯示卡支持的顯示模式,它們通常都支持640×480,800×600,1024×768等等,這些都是標準的模式。但是假如你非得設置成542×366的模式,你可能就會得到錯誤的反饋。科技在發(fā)展嗎,什么都是可能的。讓我們繼續(xù)吧! 更多內容請看J2ME游戲開發(fā)應用  Solaris基礎知識入門  Wlan組網(wǎng)----家庭專題專題,或
九.創(chuàng)建表面  這一次,我們需要比調用一個函數(shù)多一點點的東東。創(chuàng)建表面不是很難的,實際上,也是由一個單獨的函數(shù)完成的,但是首先你要填充一個描述你所要創(chuàng)建的表面的結構。給你看這個結構之前,我只想告訴你,你不必填滿所有的成員。    
    ^_^這就是它,DDSURFACEDESC2:typedef struct _DDSURFACEDESC2 {
 DWORD dwSize;
 DWORD dwFlags;
 DWORD dwHeight;
 DWORD dwWidth; union
 {
  LONG lPitch;
  DWORD dwLinearSize;
 } DUMMYUNIONNAMEN(1); DWORD dwBackBufferCount; union
 {
  DWORD dwMipMapCount;
  DWORD dwRefreshRate;
 } DUMMYUNIONNAMEN(2); DWORD dwAlphaBitDepth;
 DWORD dwReserved;
 LPVOID lpSurface;
 DDCOLORKEY ddckCKDestOverlay;
 DDCOLORKEY ddckCKDestBlt;
 DDCOLORKEY ddckCKSrcOverlay;
 DDCOLORKEY ddckCKSrcBlt;
 DDPIXELFORMAT ddpfPixelFormat;
 DDSCAPS2 ddsCaps;
 DWORD dwTextureStage;
} DDSURFACEDESC2, FAR *LPDDSURFACEDESC2;
  坦率的說,編寫DirectDraw的應用程序其實并不難。但是事情往往是這樣,80%的工作只需要我們花費20%的時間就可以完成,而剩下的20%的工作卻需要我們花費80%的時間來完成。DirectDraw編程比這還要嚴重,就筆者的看法,至少90%的工作只需要我們不到10%的時間來完成,而剩下的不到10%的工作卻至少需要我們90%的時間!結構DDSURFACEDESC就是10%的一部分,它較為復雜,它嵌套了其它的結構。讓我們看看這個怪物到底做了什么。我只說說重點的部分:  · DWORD dwSize:任何DirectX結構都有dwSize這個成員,表示結構的大小。有了它,當函數(shù)接收到指向這些結構的指針時,就可以測定結構的大小了。  · DWORD dwFlags:太好了,又有一大堆標志常量了^_^ !這些標志告訴接收函數(shù)哪些數(shù)據(jù)成員是有效的。要想使需要的數(shù)據(jù)成員有效,就必須傳遞相對應的標志常量給dwFlags,你當然可以用“”組合它們。以下是列表:  ◎ DDSD_ALL:所有的數(shù)據(jù)成員都有效。

  ◎ DDSD_ALPHABITDEPTH:表示數(shù)據(jù)成員dwAlphaBitDepth有效。
  ◎ DDSD_BACKBUFFERCOUNT:表示數(shù)據(jù)成員dwBackBufferCount有效。
  ◎ DDSD_CAPS:表示數(shù)據(jù)成員ddsCaps有效。
  ◎ DDSD_CKDESTBLT:表示數(shù)據(jù)成員ddckCKDestBlt有效。
  ◎ DDSD_CKDESTOVERLAY:表示數(shù)據(jù)成員ddckCKDestOverlay有效。
  ◎ DDSD_CKSRCBLT:表示數(shù)據(jù)成員ddckCKSrcBlt有效。
  ◎ DDSD_CKSRCOVERLAY:表示數(shù)據(jù)成員ddckCKSrcOverlay有效。
  ◎ DDSD_HEIGHT:表示數(shù)據(jù)成員dwHeight有效。
  ◎ DDSD_LINEARSIZE:表示數(shù)據(jù)成員dwLinearSize有效。
  ◎ DDSD_LPSURFACE:表示數(shù)據(jù)成員lpSurface有效。
  ◎ DDSD_MIPMAPCOUNT:表示數(shù)據(jù)成員dwMipMapCount有效。
  ◎ DDSD_PITCH:表示數(shù)據(jù)成員lPitch有效。
  ◎ DDSD_PIXELFORMAT:表示數(shù)據(jù)成員ddpfPixelFormat有效。
  ◎ DDSD_REFRESHRATE:表示數(shù)據(jù)成員dwRefreshRate有效。
  ◎ DDSD_TEXTURESTAGE:表示數(shù)據(jù)成員dwTextureStage有效。
  ◎ DDSD_WIDTH:表示數(shù)據(jù)成員dwWidth有效。  · DWORD dwheight,dwWidth:表示要創(chuàng)建表面的尺寸。以象素為單位。  · LONG lPitch:這個需要好好解釋一下。lPitch表示從畫面一行行首數(shù)據(jù)到下一行行首數(shù)據(jù)的距離,以字節(jié)為單位。例如,640×480×16,每一行有640個象素,每個象素需要兩個字節(jié)裝顏色的信息,所以pitch應該是1280個字節(jié),對不對?可能有一些顯示卡要多于1280,這每行多于的內存沒有裝置任何的圖形數(shù)據(jù),但是防御有些顯示卡不能在線性內存模式顯示圖形,你還是把多于地放在那吧。這種情況很少發(fā)生,但你最好還是考慮在內。  · LPVOID lpSurface:指向表面內存開始地址的指針。不管你使用什么顯示模式,你都可以用DirectDraw創(chuàng)建的線性地址模式操作表面象素。要想這樣,你必須鎖住表面,但這已經(jīng)超出我們現(xiàn)在所學的了。   · DWORD dwBackBufferCount:后緩沖區(qū)的數(shù)目。以后我們會在提到它。  · DWORD ddckCKDestBlt,ddckCKSrcBlt:前者為描述位轉換操作的目標顏色值,后者是源顏色值。我們將在以后的文章中具體介紹。  · DDPIXELFORMAT ddpfPixelFormat:這個結構包含了描述顯示模式的象素格式標識符。以后會具體介紹,現(xiàn)在就不多說了。  · DDSCAPS2 ddsCaps:這是最后一個重要的結構。它是一個布滿控制標志的結構。感謝菩薩,這是一個小結構,結構成員中只有一個很重要。讓我們看一看:typedef struct _DDSCAPS2{
 DWORD dwCaps;
 DWORD dwCaps2;
 DWORD dwCaps3;
 DWORD dwCaps4;
} DDSCAPS2, FAR* LPDDSCAPS2;  最重要的就是dwCaps了。第三個和第四個成員從來沒有用過,是為將來預備的。總之,dwCaps可以使用如下的值,當然可以用“”組合。以下是最為常用的,其它的你若有愛好,自己查好了。  · DDSCAPS_BACKBUFFER:指出這個表面是需要表面切換結構的后緩沖區(qū)。   
      · DDSCAPS_COMPLEX:是一個復雜表面,由主表面,一個或多個粘貼表面組成,通常是為了頁面切換。  · DDSCAPS_FLIP:指出這個表面是表面切換結構的一部分。前緩沖區(qū)緊跟著一個或多個建立好的后緩沖區(qū)。  · DDSCAPS_FRONTBUFFER:是關于表面切換結構的前緩沖區(qū)。  · DDSCAPS_LOCALVIDMEM:指出在true、local video memory【不知怎么翻譯】中建立表面。假如使用該標志,必須也同時使用DDSCAPS_VIDEOMEMORY標志,但不能同DDSCAPS_NONLOCALVIDMEM標志同時使用。  · DDSCAPS_MODEX:指出這個表面是Mode X模式(320×200或320×240)的表面。  · DDSCAPS_NONLOCALVIDMEM:指出表面建立在non-local video memory【不知怎么翻譯】中。假如定義該標志,必須也同時使用DDSCAPS_VIDEOMEMORY標志。但是不能同DDSCAPS_LOCALVIDMEM同時使用。  · DSCAPS_OFFSCREENPLAIN:這是一個簡單的離屏表面。  · DDSCAPS_OWNDC:這個表面將具有長周期的設備上下文。  · DDSCAPS_PRIMARYSURFACE:主表面。  · DDSCAPS_STANDARDVGAMODE:是標準的VGA模式表面。不能同DDSCAPS_MODEX同用。  · DDSCAPS_SYSTEMMEMORY:建立在系統(tǒng)內存里的表面。  · DDSCAPS_VIDEOMEMORY:這個表面建立在顯示內存里。  天啊,終于介紹完了這個結構。現(xiàn)在我們預備建立表面吧。第一步當然是填充DDSURFACEDESC2結構。Microsoft推薦大家當你使用一個結構之前,你應該把它先初始化為0。有鑒于此,我經(jīng)常使用這樣一個宏:#define INIT_DXSTRUCT(dxs) { ZeroMemory(&dxs, sizeof(dxs)); dds.dwSize = sizeof(dxs); }
  它可以用于任何一個DirectX結構,因為它們都有dwSize成員,所以這是很方便的。假如你以前從來沒有看過ZeroMemory()這個函數(shù),它只是由函數(shù)memset()擴充來的宏,在Windows的頭文件中用#define定義好了,所以你不需要用#indlude添加任何東西就可以用它。
初始化了結構之后,你得根據(jù)實際情況設置表面了。對于主表面,你需要ddsCaps和dwBackBufferCount,對于離屏緩沖區(qū),你也需要dwHeight和dwWidth,但不需要dwBackBufferCount。對于一些表面你可能還需要顏色值,但我們不把它弄得太復雜了。填充完結構后,你需要調用IDirectDraw7::CreateSurface()函數(shù),原形是這樣:HRESULT CreateSurface(

 LPDDSURFACEDESC2 lpDDSurfaceDesc,
 LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface,
 IUnknown FAR *pUnkOuter
);
  這些參數(shù)的意義可能你也能猜出個大概了,究竟我們已經(jīng)習慣了這些瘋狂的DirectX素材:  · LPDDSURFACEDESC2 lpDDSurfaceDesc:表示要創(chuàng)建表面的描述結構。當然是個指針了。  · LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface:為指向表面指針的指針。此參數(shù)在此函數(shù)調用成功后填充。為什么要使用指向指針的指針呢?這是因為我們的任務就是分配一片表面內存區(qū)域,這樣只能使用指針(表面指針)作為操作該表面內存區(qū)域的標志,返回值應該是該指針值而不是該指針所表示的內容(具體的表面)。當我們使用函數(shù)參數(shù)傳遞該值時,又只能使用指針(即指針的指針)修改表面指針的內容而不是表面指針所代表的表面內存區(qū)域。(理論復雜,使用簡單,不明白不要太在意)   · IUnknown FAR *pUnkOuter:看過這個模式吧,無論何時調用pUnkOuter,都是關于COM應用的,我們不想在這兒浪費時間,設置為NULL好了。  來個實例吧,你會明白一切的。希望在實例里,我們要一個主表面和一個緊隨主表面的后緩沖區(qū),還有一個離屏緩沖區(qū)用來放置位圖。假設我們已經(jīng)得到了IDirectDraw7接口指針,代碼如下:DDSURFACEDESC2 ddsd; // surface description structure
LPDIRECTDRAWSURFACE7 lpddsPrimary = NULL; // primary surface// set up primary drawing surface
INIT_DXSTRUCT(ddsd); // initialize ddsd
ddsd.dwFlags = DDSD_CAPS DDSD_BACKBUFFERCOUNT; // valid flags
ddsd.dwBackBufferCount = 1; // one back buffer
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE // primary surface
DDSCAPS_COMPLEX // back buffer is chained
DDSCAPS_FLIP // allow page flipping
DDSCAPS_VIDEOMEMORY; // create in video memory// create primary surface
if (FAILED(lpdd7->CreateSurface(&ddsd, &lpddsPrimary, NULL)))
{
 // error-handling code here
}
  你當然還可以用CreateSurface()函數(shù)創(chuàng)建復雜表面,只是使用DDSCAPS_COMPLEX標志罷了。由于剛才我們創(chuàng)建了一個后緩沖區(qū),所以我們還得必須得到指向它的指針。那就得調用IDirectDrawSurface7::GetAttachedSurface()函數(shù)了:HRESULT GetAttachedSurface(
 LPDDSCAPS2 lpDDSCaps,
 LPDIRECTDRAWSURFACE7 FAR *lplpDDAttachedSurface
);
  參數(shù)很簡單啦:  · LPDDSCAPS2 lpDDSCaps:指向創(chuàng)建后緩沖區(qū)表面的DDSCAPS2結構。你就可以使用DDSCAPS2結構中相應的成員了。  · LPDIRECTDRAWSURFACE7 FAR *lplpDDAttachedSurface:后緩沖區(qū)表面指針的地址。簡單理解為聲明一個指針,然后把指針的地址傳遞給該參數(shù)。  看看下面的代碼就明白了:LPDIRECTDRAWSURFACE7 lpddsBack = NULL; // back buffer// get the attached surface
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
if (FAILED(lpddsPrimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsBack)))
{
 // error-handling code here
}   感覺有點兒入門了嗎?假如你很難記住以上步驟,那么你是一個正常人,反復運用就會熟悉了。沒有人能記住所有的龐大的結構成員和標志常量,這就是我們手邊總是預備程序員參考手冊或者擁有MSDN Library CD的原因了^_^ !OK,最后一步是建立離屏緩沖區(qū)。假設它的寬400,高300,(單位是象素)代碼如下:LPDIRECTDRAWSURFACE7 lpddsOffscreen = NULL; // offscreen buffer// set up offscreen surface
INIT_DXSTRUCT(ddsd); // initialize ddsd
ddsd.dwFlags = DDSD_CAPS DDSD_WIDTH DDSD_HEIGHT; // valid flags
ddsd.dwWidth = 400; // set width
ddsd.dwHeight = 300; // set height
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN // offscreen buffer
DDSCAPS_VIDEOMEMORY; // video memory// create offscreen buffer
if (FAILED(lpdd7->CreateSurface(&ddsd, &lpddsOffscreen, NULL)))
{
 // error-handling code here
}
  表面這些學問就介紹到這兒,還有好多東西要介紹,可是唯一的問題是文章太長了,我們先暫停吧。你現(xiàn)在可以建立一個最基本的,但是什么也不顯示的表面。   千萬記住了,你使用的每一個DirectDraw接口和所有的表面,用完后一定要釋放(Release)它們啊!切記、切記!!!!!!!十.總結  很抱歉在這里中斷了,尤其是你還沒有看到顯示的圖形,但關于圖形有太多的內容了,不是三言兩語就能說清除的,所以放到下兩章。下一章討論DirectDraw中的調色板和象素,再下下一章討論DirectDraw中的位圖。出色在后面哦!請耐心期待。



發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 明溪县| 迁西县| 平凉市| 富平县| 安康市| 茂名市| 河北省| 泾源县| 唐山市| 大化| 阿城市| 山西省| 田林县| 南溪县| 新津县| 昌邑市| 儋州市| 锡林浩特市| 平和县| 离岛区| 阜阳市| 垫江县| 保山市| 清河县| 交口县| 固始县| 宁陵县| 永州市| 永福县| 内乡县| 兴城市| 磴口县| 卢龙县| 金湖县| 石楼县| 新干县| 漯河市| 梁平县| 南京市| 嵊州市| 公主岭市|