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

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

DirectX游戲開發入門

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

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

七.建立DIRECTDRAW對象   
      象我前面說過的,有三種方法。我們可以用兩個DIRECTDRAW函數中的任何一個,或者直接調用COM對象。讓我們每一個都試試,使我們自己熟悉它們。我將告訴你的最后一個方法可能是目前為止最簡單的,可能你會喜歡用它。至于另外兩個,打眼兒一看,你會覺得有些希奇。首先,看看DirectDrawCreate():
HRESULT WINAPI DirectDrawCreate(
GUID FAR *lpGUID,
LPDIRECTDRAW FAR *lplpDD,
IUnknown FAR *pUnkOuter
);    看起來是不是有點兒復雜?HRESULT返回的類型是DirectDraw函數的標準。假如成功,返回值是DD_OK。假如失敗,函數將返回一個錯誤常量,有幾個錯誤常量供選擇,但我不想細講,更不想列出這些常量,反正你可以通過幫助文件隨時查閱它們。但有一件事兒我得告訴你,有兩個非常有用的宏可以幫助你知道函數調用成功與否:SUCCEEDED()和FAILED()。從字面上你就知道它們的分工了,是不是?只要把函數放到宏里面,你就知道結果了。無論如何,我們還得看看函數的參數:  · GUID FAR *lpGUID:是一個全局唯一標識符(GUID)的地址,代表將要創建的驅動程序。假如該參數是NULL,那么該調用指向當前的顯示驅動程序。新版本的DirectDraw答應向該參數傳遞下列兩種標志之一,以控制當前顯示的行為:   DDCREATE_EMULATIONONLY:DirectDraw只使用仿真(HEL),不使用硬件支持特性?! ?DDCREATE_HARDWAREONLY:DirectDraw對象不使用仿真特性。只能使用硬件抽象層(HAL),假如硬件不能支持應用程序,將不再尋求硬件仿真層(HEL)的支持而返回錯誤信號。  · LPDIRECTDRAW FAR *lplpDD:表示假如調用成功則返回有效的DirectDraw對象指針的地址,它是DirectDraw對象指針的指針(“DD”表示DirectDraw,“lp”表示32位長指針,“lplp”表示長指針的長指針)。應用程序一般需要使用此指針的地址(即DirectDraw對象指針)初始化DirectDraw對象。  · IUnknown FAR *pUnkOuter:這是為高級COM應用保留的參數,設置為NULL好了?! 〔灰晃伊_里羅嗦的解釋嚇倒,實際應用起來很簡單,解釋這么多,不過是為了讓你明白根本道理。現在有一個問題,這個函數給你一個指向IDirectDraw接口的指針,但我們想要一個指向IDirectDraw7接口的指針,我們應該怎么做呢?一旦DirectDraw應用程序通過DirectDrawCreate()函數獲得了指向DirectDraw對象的指針,COM就有一種機制可以用來查看該對象是否支持其它接口。IUnknown的QueryInterface()方法使得你能夠確定一個對象是否支持一個特定的接口:
HRESULT QueryInterface(
 REFIID iid, // Identifier of the requested interface
 void **ppvObject // Address of output variable that receives the
);
  第一個參數是一個要查詢的對象的引用標識符。對于IDirectDraw7來說就是IID_IDirectDraw7。使用它,你必須把dxguid.lib鏈接入你的項目中;第二個參數是一個變量的地址,我們應該在程序的頭部先聲明一個LPDIRECTDRAW7類型的指針,再把指針的地址傳遞給這個參數。假如你使用的是Visual C++6.0,你在這兒或許還需要一個類型強制符。假如機器支持你指定的接口,函數將返回一個指向該接口的指針。通過該指針,代碼就獲得對新接口的方法的訪問。假如函數調用成功,返回值是S_OK。  現在我們有了兩個接口指針:一個是IDirectDraw接口,另一個是IDirectDraw7。后一個是我們想要的;前一個就沒有用了。我們注重,在代碼中每當找到一個新的有效對象時,前一個對象就通過Release()函數被釋放掉。這個函數很簡單:ULONG Release(void);
  返回的值是一個參考數字,只有在程序測試和調試時才用得著這個數字。為了安全起見,你還應該把釋放了的指針賦值為NULL。我們也通常在聲明這樣的指針時設置它為NULL。你跟上我的節奏了嗎?可能要記憶的東西太多了,但是你不得不記憶。讓我們把談到的這些做個實例吧,實例的目的是得到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;
}
  現在,假如你是一個C程序員,你可能被調用QueryInterface()和Release()這兩個函數的方法弄得有點模糊。你以前可能看過“->”這個符號,在C語言的結構部分,當結構聲明了一個指針變量,調用結構成員時,就用“結構指針名->結構成員”,同樣的道理,只是這里把結構成員換成了函數。既然說到這個話題,我就介紹一下另一個C++符號,范圍定義符號“::”,它是表示從屬關系的符號,舉個例子你就明白了:比如QueryInterface()函數是屬于IUnknown類的,就可以表示為IUnknown::QueryInterface()。我們將來會經常用到這個符號的,所以記住它?! ≌f實在的,以上的主要目的是為了演示怎樣使用QueryInterface()方法,它是所有DirectX接口的一部分,所以讓我們往下進行。我們將直接使用COM方法獲得接口指針。這種方法的好處是你可以立即獲得IDirectDraw7接口指針,不用象剛才那么麻煩。首先,你必須得初始化COM,象這樣:HRESULT CoInitialize(LPVOID pvReserved);
  不能在輕易了,你必須把參數設置為NULL。當你結束COM調用,你需要拋棄它,也很簡單:void CoUninitialize(void);
  我通常在DirecX程序的一開始就調用CoInitialize()函數,在程序的最末端,當我釋放了所有的DirectX對象后,使用CoUninitialize()。一旦你初始化了COM,你就可以用CoCreateInterface()函數得到你想要的指針,它看起來有點丑陋: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。參數需要好好解釋一下,看下面:  · REFCLSID rclsid:這是一個類標識符(不要同GUID搞混了哦),有為它預備好的常量標識符供你選擇。對于IDirectDraw7來說,使用CLSID_DirectDraw。注重沒有版本號,因為它是類標識符,不是接口標識符。  · LPUNKNOWN pUnkOuter:這個同我們在DirectDrawCreate()中看到的一樣,設置為NULL?!  ?DWORD dwClsContext:這個必需的值叫作執行上下文,它定義了控制新生成對象的代碼將要執行的方式。這個值可以從CLSCTX列表中選取,對于我們現在的情況,我們用CLSCTX_ALL,它包含了所有可能的值?!  ?REIID riid:我們在QueryInterface()中看過它。這個IID是IID_DirectDraw7?!  ?LPVOID *ppv:依然同DirectDrawCreate()中的一樣,是指向接口指針的地址?! ≌{用這個函數將取代我們上一個方法中的DirectDrawCreate()、QueryInterface()和Release()三個函數,所以簡捷一些。當然,使用哪種隨便你了。直接調用COM比我們先前用的方法少了一個多于地接口指針。一旦你用CoCreateInstance()建立了一個對象,你還得調用Initialize()函數初始化這個對象。在C++里可能寫成這樣IDirectDraw7::Initialize()。以下是它的原形:HRESULT Initialize(GUID FAR *lpGUID);
  將使用同DirectDrawCreate()中一樣的GUID,就是NULL。在我們繼續前,讓我給你看一個使用COM創建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對象的最難的兩種方法你已經學會了,那就讓我們看看最簡單的方法吧! 它只有一步,沒有多于的接口指針,不用設置COM,什么都沒有。就是下面這個函數:DirectDrawCreateEx(
 GUID FAR *lpGuid,
 LPVOID *lplpDD,
 REFIID iid,
 IUnknown FAR *pUnkOuter
);
  所有的參數我們看起來都比較熟悉,因為我們剛才看過它們了。第一個,第二個和第四個參數同DirectDrawCreate()中的一樣,只是這里需要用(void**)來修飾一下我們接口指針的地址——別問我為什么,這不是我的主意。第三個參數,riid,是我們在函數CoCreateInstance()中傳遞的接口ID,所以我們就用IID_IDirectDraw7。就這樣,無論用哪種方法,我們得到了我們的DirectDraw對象,我們可以繼續使用這個對象了。要做的頭兩件事是設置協作等級和顯示協議。
八.作等級和顯示模式  我不需要說太多。Windows編程設置協作級別你只需要調用IDirectDraw7::SetCoOperativeLevel()函數;設置顯示模式你就調用IDirectDraw7::SetDisplayMode()函數。就這么簡單!先來看看協作級別。這就是函數原形:

   
   
HRESULT SetCooperativeLevel(
 HWND hWnd,
 DWORD dwFlags
);
  返回的類型是HRESULT,你應該已經熟悉它了。對于所有的DirectX函數調用,你都可以用SUCCEEDED()和FAILED()宏檢測調用的結果。以下是函數SetCooperativeLevel()的參數:  · HWND hWnd:很熟悉吧!傳遞主窗口的句柄給它,使Windows知道誰將使用它的資源。   · DWORD dwFlags:這個也很眼熟吧!每次我們看到dwFlags參數,幾乎都有一個大的標志常量列表供我們選擇,并且可以用“”組合。這次也不會讓你失望的哦!   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:表示常規的Windows應用程序,不能與DDSCL_ALLOWMODEX、DDSCL_EXCLUSEIVE或DDSCL_FULLSCREEN標志同時使用,在該模式下運行的應用程序不能進行頁交換或者更改主調色板?! ?6.SCL_NOWINDOWCHANGES:防止DirectDraw最小化或恢復應用程序窗口。
 
  還有幾個標志常量我們暫時用不到,就不說了。由于我們要建立一個全屏的640×480×16的顯示模式,所以我們得這樣設置:lpdd7->ooperativeLevel(hwnd, DDSCL_ALLOWREBOOT DDSCL_EXCLUSIVE DDSCL_FULLSCREEN);
  現在協作級別已經設置好了,讓我們再看看改變顯示模式的函數:HRESULT SetDisplayMode(
DWORD dwWidth,
DWORD dwHeight,
DWORD dwBPP,
DWORD dwRefreshRate,
DWORD dwFlags
);   別忘了用宏去檢測調用函數的成功或失?。〈蠖鄶档膮低懔舷氲牟畈欢啵骸  ?DWORD dwWidth,dwHeight:以象素為單位,新顯示模式的尺寸?!  ?DWORD dwBPP:新顯示模式的色彩深度。就是每一個象素有多少位字節。可以設置為8,16,24或32。警告:很多顯示卡不支持24-bits?!  ?DWORD dwRefreshRate:屏幕的刷新頻率。但你最好設置為0,使用默認的刷新頻率?!  ?DWORD dwFlags:對不起,這次沒有列表了^_^,唯一的選擇是DDSDM_STANDARDVGAMODE,它把顯示模式設置為0x13(DOS程序員的好朋友),取代了Mode X的320×200×8的模式。假如你還想使用其它的模式(你可能經常需要),沒有問題,把它設置為0好了?! ∵@些就是顯示模式的設置,事先最好了解你的顯示卡支持的顯示模式,它們通常都支持640×480,800×600,1024×768等等,這些都是標準的模式。但是假如你非得設置成542×366的模式,你可能就會得到錯誤的反饋??萍荚诎l展嗎,什么都是可能的。讓我們繼續吧! 更多內容請看J2ME游戲開發應用  Solaris基礎知識入門  Wlan組網----家庭專題專題,或
九.創建表面  這一次,我們需要比調用一個函數多一點點的東東。創建表面不是很難的,實際上,也是由一個單獨的函數完成的,但是首先你要填充一個描述你所要創建的表面的結構。給你看這個結構之前,我只想告訴你,你不必填滿所有的成員。    
    ^_^這就是它,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這個成員,表示結構的大小。有了它,當函數接收到指向這些結構的指針時,就可以測定結構的大小了。  · DWORD dwFlags:太好了,又有一大堆標志常量了^_^ !這些標志告訴接收函數哪些數據成員是有效的。要想使需要的數據成員有效,就必須傳遞相對應的標志常量給dwFlags,你當然可以用“”組合它們。以下是列表:  ◎ DDSD_ALL:所有的數據成員都有效。

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

 LPDDSURFACEDESC2 lpDDSurfaceDesc,
 LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface,
 IUnknown FAR *pUnkOuter
);
  這些參數的意義可能你也能猜出個大概了,究竟我們已經習慣了這些瘋狂的DirectX素材:  · LPDDSURFACEDESC2 lpDDSurfaceDesc:表示要創建表面的描述結構。當然是個指針了?!  ?LPDIRECTDRAWSURFACE7 FAR *lplpDDSurface:為指向表面指針的指針。此參數在此函數調用成功后填充。為什么要使用指向指針的指針呢?這是因為我們的任務就是分配一片表面內存區域,這樣只能使用指針(表面指針)作為操作該表面內存區域的標志,返回值應該是該指針值而不是該指針所表示的內容(具體的表面)。當我們使用函數參數傳遞該值時,又只能使用指針(即指針的指針)修改表面指針的內容而不是表面指針所代表的表面內存區域。(理論復雜,使用簡單,不明白不要太在意)   · IUnknown FAR *pUnkOuter:看過這個模式吧,無論何時調用pUnkOuter,都是關于COM應用的,我們不想在這兒浪費時間,設置為NULL好了。  來個實例吧,你會明白一切的。希望在實例里,我們要一個主表面和一個緊隨主表面的后緩沖區,還有一個離屏緩沖區用來放置位圖。假設我們已經得到了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()函數創建復雜表面,只是使用DDSCAPS_COMPLEX標志罷了。由于剛才我們創建了一個后緩沖區,所以我們還得必須得到指向它的指針。那就得調用IDirectDrawSurface7::GetAttachedSurface()函數了:HRESULT GetAttachedSurface(
 LPDDSCAPS2 lpDDSCaps,
 LPDIRECTDRAWSURFACE7 FAR *lplpDDAttachedSurface
);
  參數很簡單啦:  · LPDDSCAPS2 lpDDSCaps:指向創建后緩沖區表面的DDSCAPS2結構。你就可以使用DDSCAPS2結構中相應的成員了。  · LPDIRECTDRAWSURFACE7 FAR *lplpDDAttachedSurface:后緩沖區表面指針的地址。簡單理解為聲明一個指針,然后把指針的地址傳遞給該參數。  看看下面的代碼就明白了: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,最后一步是建立離屏緩沖區。假設它的寬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
}
  表面這些學問就介紹到這兒,還有好多東西要介紹,可是唯一的問題是文章太長了,我們先暫停吧。你現在可以建立一個最基本的,但是什么也不顯示的表面。   千萬記住了,你使用的每一個DirectDraw接口和所有的表面,用完后一定要釋放(Release)它們??!切記、切記!?。。。。?!十.總結  很抱歉在這里中斷了,尤其是你還沒有看到顯示的圖形,但關于圖形有太多的內容了,不是三言兩語就能說清除的,所以放到下兩章。下一章討論DirectDraw中的調色板和象素,再下下一章討論DirectDraw中的位圖。出色在后面哦!請耐心期待。



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久精品国产综合| 欧美大胆a视频| 亚洲色图第三页| 亚洲精品视频二区| 国产亚洲一区二区在线| 亚洲激情视频在线| 国产精品丝袜久久久久久高清| 欧美最近摘花xxxx摘花| 亚洲欧美自拍一区| 日韩中文字幕亚洲| 亚洲国产精品成人va在线观看| 国产精品入口日韩视频大尺度| 久久久91精品国产一区不卡| 中文字幕亚洲在线| 久久久亚洲影院你懂的| 欧美一区三区三区高中清蜜桃| 国产精品福利片| 日韩在线观看免费av| 亚洲男人av电影| 777午夜精品福利在线观看| 国产成人福利网站| 性欧美在线看片a免费观看| 欧美美女15p| 日韩精品免费看| 免费97视频在线精品国自产拍| 亚洲xxxx18| 国产成+人+综合+亚洲欧洲| www.日本久久久久com.| 亚州av一区二区| 欧美精品在线免费| 亚洲香蕉成人av网站在线观看| 麻豆成人在线看| 成人性生交xxxxx网站| 国产成人精品亚洲精品| 国产精品黄色av| 最新的欧美黄色| 成人精品一区二区三区电影免费| 亚洲最新av网址| 中国china体内裑精亚洲片| 国产精品老女人精品视频| 黑人巨大精品欧美一区二区一视频| 欧美激情久久久| 欧美精品午夜视频| 欧美日韩综合视频网址| 欧美一区视频在线| 欧美成人免费一级人片100| 国外视频精品毛片| 青草青草久热精品视频在线观看| 国产美女久久精品| 亚洲欧美国产精品va在线观看| 不卡在线观看电视剧完整版| 日韩av电影手机在线观看| 成人国产精品久久久| 亚洲精品大尺度| 国产成人精品一区| 成人av电影天堂| 欧美www视频在线观看| 亚洲精品98久久久久久中文字幕| 日韩精品中文在线观看| 色99之美女主播在线视频| 日韩av在线免费观看一区| 日韩在线观看你懂的| 久久久97精品| 国产99视频精品免视看7| 法国裸体一区二区| 欧美高跟鞋交xxxxxhd| 奇米影视亚洲狠狠色| 麻豆国产va免费精品高清在线| 国产极品jizzhd欧美| 奇门遁甲1982国语版免费观看高清| 91国偷自产一区二区三区的观看方式| 国产日韩综合一区二区性色av| 日韩精品免费看| 一区二区三区国产在线观看| 欧美成人激情视频| 宅男66日本亚洲欧美视频| 91高清视频免费观看| 精品性高朝久久久久久久| 久久综合九色九九| 中文国产成人精品久久一| 亚洲男女性事视频| 91亚洲精品在线观看| 欧美激情综合色综合啪啪五月| 高潮白浆女日韩av免费看| 久久综合色88| 91九色精品视频| 国产精品主播视频| 日韩在线视频一区| 欧美性xxxx极品高清hd直播| 日韩av一区二区在线| 91精品国产自产在线观看永久| 不卡av在线网站| 最近2019中文字幕第三页视频| 在线视频日本亚洲性| 国产精品久久久av| 久久手机免费视频| 日韩天堂在线视频| 国产免费成人av| 在线精品视频视频中文字幕| 日韩成人在线免费观看| 亚洲欧洲av一区二区| 亚洲第一区中文99精品| 精品呦交小u女在线| 欧美日韩在线视频一区| 国产精品视频1区| 在线精品视频视频中文字幕| 久久精品免费电影| 国内精品久久久久影院优| 中文字幕精品影院| 97超碰蝌蚪网人人做人人爽| 国产在线视频欧美| 97热在线精品视频在线观看| 自拍偷拍免费精品| 国产精品亚洲一区二区三区| 95av在线视频| 欧美性极品少妇精品网站| 亚洲毛片在线观看.| 色狠狠久久aa北条麻妃| 亚洲一区二区三区四区在线播放| 日韩av一区二区在线| 欧美激情videoshd| 亚洲国产精品va在线看黑人动漫| 亚洲欧洲一区二区三区久久| 日韩视频免费观看| 国产日产久久高清欧美一区| 国产丝袜高跟一区| 在线日韩日本国产亚洲| 深夜福利91大全| 久久99热这里只有精品国产| 色yeye香蕉凹凸一区二区av| 日韩在线视频观看| 国产视频亚洲精品| 国内精品久久久久影院 日本资源| 欧美日韩xxx| 国产视频在线观看一区二区| 欧美日韩美女视频| 日韩高清免费在线| 日韩av影院在线观看| 精品电影在线观看| 亚洲福利精品在线| 国产成人精品综合久久久| 51精品在线观看| 欧美人与性动交a欧美精品| www欧美日韩| 亚洲视频在线免费观看| 精品国产一区二区三区在线观看| 亚洲在线视频福利| 久久国产天堂福利天堂| 国产精品欧美激情| 欧美亚洲成人网| 日韩成人xxxx| 日韩成人黄色av| 在线精品国产成人综合| 97精品视频在线播放| 欧美日韩国产精品一区| 国产日韩精品在线观看| 全球成人中文在线| 国产亚洲视频在线观看| 国产97在线|日韩| 伊人男人综合视频网| 欧美又大又粗又长| 亚洲毛片一区二区| 91wwwcom在线观看| 国产精品黄色影片导航在线观看|