• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            DirectX詳解

            ?
            DirectX是一套為Windows程序提供對系統硬件更緊密控制的組件。(表1列出了DirectX?5.0?
            的組件及其作用)。那么,緊密控制是什么意思呢??

            組件?用途?
            DirectDraw?高速2D圖象?
            DirectSound?短響應時間聲音輸出?
            Direct3D?高速3D圖象?
            DirectInput?面向游戲的對游戲桿和其它輸入設備的訪問?
            DirectSetup?方便的安裝DirectX組件?
            DirectPlay?面向游戲的通信和網絡支持?
            DirectShow?視頻流支持?
            DirectAnimation?動畫錄放支持?


            DirectX提供的硬件控制常常被描述成底層控制,這會使人聯想起位操作和其它討厭的事?
            情。實際上,DirectX組件包含許多高層API,使得象復制位圖和播放聲音等復雜的工作變?
            得相當簡單。用"為程序提供比過去更好的對硬件的控制"來形容DirectX更準確。這在?
            Windows中是一個顯著的特性,因為在Windows中,資源是共享的,并由操作系統控制。?

            DirectX組件遵守稱為COM的二進制對象的工業標準。?

            開始DirectX?
            下面從DirectX的安裝開始講起。大多數情況下,某個好玩的游戲就會為系統安裝DirectX。?
            為得到最新的版本,應該從最新的Microsoft?Platform?SDK中將DirectX安裝到系統中。?
            可以在http://www.microsoft.com/msdn站點或者MSDN光盤中找到platform?SDK。缺省情?
            況下,Microsoft?Platform?SDK被安裝到缺省驅動器根目錄下的\MSSDK目錄中。DirectX?
            的頭文件安裝在\MSSDK\INCLUDE目錄中,Lib文件安裝在\MSSDK\LIB目錄中。?

            Platform?SDK包含了一些非常好的DirectX例子和文檔。早期發布的DirectX?文檔非常粗?
            略而且有些是錯誤的,現在的版本已經極大地改正了這一問題。最好要熟悉這些文檔。?

            現在已經為安裝利用DirectX的程序做好了準備。所幸的是,不必一次就處理DirectX的全?
            部功能。DirectX是一套可以分別使用的組件。實際上,在編程概念中,DirectX的不同部?
            分互相沒有聯系。它們僅僅是具有相同的設計風格和目標:使Windows的游戲編程變得容易。?

            使用DirectX組件的程序有什么特殊的地方嗎?根本沒有。使用DirectX組件的程序是基于?
            Win32的程序,它們使用普通Win32?API集,并且可以訪問所有可以獲得的操作系統工具。?
            實際上,DirectX既可以用于GUI程序,也可以用于控制臺程序。可以直接用Petzold-style?
            SDK編程開發程序,也可以用基本類庫,如MFC。總的說,唯一的要求是大多數DirectX組?
            件在程序中需要HWND,所以至少要有一個窗口。?

            雖然DirectX組件是分離的,但是每個組件的實現風格和使用都是相同的。DirectInput是?
            學習DirectX的非常好的出發點,原因是DirectInput是最簡單的組件之一。?
            用力?
            以后在游戲中要"用力",這是電影《星球大戰》中的說法,因為DirectInput中加入了相?
            當令人陶醉的力反饋支持。DirectX?5.0以前,DirectInput支持從鼠標和鍵盤讀取輸入,?
            這是一個有用但卻令人厭煩的特性。DirectX?5.0中,DirectInput被擴充到支持具有以物?
            理力的形式向用戶傳播反饋的能力的設備。?

            如果不能立即理解上面的內容,下面就用一個游戲進行解釋。假設你剛啟動了你最喜歡的超?
            現實3D越野賽車游戲,正手握力反饋游戲桿。在起跑線上,你可以聽到賽車引擎的空轉聲,?
            同時也能夠通過游戲桿感覺到賽車引擎的空轉!比賽開始后,你可以感覺到引擎高速旋轉的?
            嗡嗡震動。當行駛到賽程中崎嶇的地段時,你將會不停的感覺到電子碰撞。賽車在整個賽場?
            上撞來撞去,你的游戲桿也會如此。賽車車輪卡在車轍中導致賽車被拉向左邊,游戲桿也會?
            被拉向左邊!整個過程中你可以感覺到每次顛簸、刮擦、撞擊和撞毀。?

            剖析DirectInput?
            DirectInput由三個對象組成:DirectInput,?DirectInputDevice,?和DirectInputEffect?(見?
            表2)。DirectInput是一個高層的對象,通過DirectInput對象可以對相關的輸入設備進行?
            基本的初始化和查找。DirectInput對象最終用來創建低層的DirectInputDevice對象。?
            DirectX中的每個主要組件都采用相同的方法,首先創建高層對象,如DirectInput或?
            DirectSound對象,然后創建低層對象與硬件進行實際的通信。?

            表2:?DirectInput對象?
            對象?說明?
            DirectInput?封裝高層DirectInput功能,列舉設備并用來創建DirectInputDevice對象。?
            DirectInputDevice?與物理輸入設備的接口,例如游戲桿,包括收集和設置設備狀態信息的?
            接口,并且用來創建DirectInputEffect對象?(對于力反饋設備)。?
            DirectInputEffect?封裝能夠在力反饋設備上"播放"的簡單效果,提供啟動、停止和設置?
            力反饋效果等功能。?


            DirectInput對象是三個對象中最容易理解的。實際上,它在一個接口形式IDirectInput?(見?
            表3)中只提供五個函數。這是DirectInput的一個非常重要的部分,因為這是出發點。?

            表3:IdirectInput接口:?
            成員函數?說明?
            CreateDevice?創建一個DirectInputDevice對象并返回一個指向其IdirectInputDevice接?
            口的指針。?
            EnumDevices?為找到的與給定標準匹配的每個設備調用一個回調函數,每個回調函數提供一?
            個GUID,可以用在CreateDevice中創建DirectInputDevice對象。?
            GetDeviceStatus?測試物理設備是否連接到系統。?
            Initialize?如果DirectInput對象是使用CoCreateInstance創建的,那么在使用前必須調?
            用Initialize成員。如果DirectInput對象是使用DirectInputCreate創建的,那么就已?
            經初始化過了。?
            RunControlPanel?為設備運行Windows?Control?Panel程序,讓用戶安裝新設備或者更改已?
            有設備的配置。?游戲桿校準可以在此處做。?
            創建DirectInput對象?
            為了創建DirectInput對象并得到其IdirectInput接口指針,應該在程序初始化階段使用?
            兩種方法之一完成。?

            第一種方法相當簡單。DirectX提供了一個助手函數DirectInputCreate來創建并初始化?
            DirectInput對象。它與所有DirectInput的函數、接口和宏定義都在頭文件DINPUT.H中?
            聲明。實際的函數體在DINPUT.LIB文件中。DirectInputCreate如下定義:?

            HRESULT?WINAPI?DirectInputCreate(?
            HINSTANCE?hinst,?
            DWORD?dwVersion,?
            LPDIRECTINPUT?*?lplpDirectInput,?
            LPUNKNOWN?punkOuter?
            );?

            第一個參數是應用程序的實例。第二個參數是程序需要的DirectInput版本,通常使用?
            DIRECTINPUT_VERSION宏,定義為當前版本。第三個參數最重要,如果對COM非常陌生的化?
            就很難理解,它是指向IdirectInput接口的指針的地址。程序中應該定義一個LPDIRECTINPUT?
            類型的變量(可以是全局的)并將其地址作為第三個參數傳遞給DirectInputCreate。?

            最后一個參數叫作punkOuter,與COM技術中的聚合有關,可以用NULL安全的忽略。返回?
            值是一個HRESULT,是COM的標準返回類型,可以將返回值與可能的返回值比較,也可以使?
            用COM宏定義SUCCESS或FAILED來檢查。?

            使用DirectInputCreate能夠容易地創建高層對象并得到其主接口指針。這是DirectX的又?
            一個設計方法,每個DirectX組件都提供助手函數來創建高層對象,例如DirectInputCreate?
            或DirectDrawCreate。在程序中可以用這些助手函數創建DirectX對象,然而,這些函數?
            實際上創建的是COM對象。這個工作也可以用叫作CoCreateInstance的標準Win32?API函?
            數來完成。這就引出了創建DirectInput對象的第二中方法。?

            在Win32中用CoCreateInstance創建COM對象非常普遍。如果程序中已經使用?
            CoCreateInstance創建了其他COM對象,開發者可能就會希望也用它來創建DirectX對象。?
            因為COM對象在安裝時就在系統中注冊過,所以唯一需要知道的就是對象的GUID,用它來?
            創建一個實例。創建DirectX對象需要的全部GUID都在頭文件中聲明,并在庫文件?
            DXGUID.LIB中定義。可以將一個預定義的GUID傳遞給CoCreateInstance,讓Windows為你?
            創建對象。CoCreateInstance定義如下:?

            STDAPI?CoCreateInstance(?
            REFCLSID?rclsid,?
            LPUNKNOWN?pUnkOuter,?
            DWORD?dwClsContext,?
            REFIID?riid,?
            LPVOID?*?ppv?
            );?


            第一個參數是要創建對象的GUID,DirectX定義的GUID是叫作CLSID_DirectInput的GUID?
            結構變量。第二個參數是熟悉的pUnkOuter,同樣可以用NULL忽略。第三個參數dwClsContext?
            定義COM對象在何處創建,DirectX只支持進程內服務器,所以必須使用?
            CLSCTX_INPROC_SERVER。?

            第四個參數是兩種方法真正的不同之處。記住COM對象對外提供接口,與對象本身一樣,接?
            口也用GUID識別。使用第一種方法,不能選擇得到的接口,總是得到IdirectInput。使用?
            CoCreateInstance可以請求對象所支持的任何接口,方法是使用為接口預定義的GUID。但?
            是在DirectInput這是沒有意義的,因為DirectInput對象的唯一有用的接口就是?
            IdirectInput。其它DirectX組件支持多個有用的接口。(例如,DirectDraw對象可以用?
            IdirectDraw或IDirectDraw2接口操作。)?

            最后一個參數是程序中接口指針變量的實際地址。?

            現在就擁有了對象和對象的一個接口。CoCreateInstance方法還需要另外一步:必須要首?
            先調用一個接口函數初始化對象。DirectInputCreate提供的是一個已經初始化過的?
            DirectInput對象,但CoCreateInstance沒有特定于DirectInput的認識,因此必須調用?
            IdirectInput接口的初始化成員函數。?假設如下定義IdirectInput接口指針變量:?

            LPDIRECTINPUT?g_lpDI?

            可以如下調用初始化函數:?

            g_lpDI->Initialize(?hInstance,?DIRECTINPUT_VERSION);?

            既然選擇采取這種標準方法創建對象,就不得不注意COM需要的其他標準,例如需要調用?
            CoInitialize和CoUninitialize。?
            使用DirectInput對象?
            一旦擁有了DirectInput對象,就可以用它來創建DirectInputDevice對象,來管理系統中?
            特定的設備。創建DirectInputDevice對象要使用CreateDevice函數,它是作為?
            IdirectInput接口一部分的五個函數之一。CreateDevice需要所請求設備的GUID,返回新?
            DirectInputDevice對象的IdirectInputDevice接口指針。?

            HRESULT?CreateDevice(?
            REFGUID?rguid,?
            LPDIRECTINPUTDEVICE?*lplpDirectInputDevice,?
            LPUNKNOWN?pUnkOuter?
            );?

            這些內容看起來很熟悉,因為它與CoCreateInstance和DirectInputCreate類似。但是,?
            現在還沒有完全準備好開始DirectInputDevice對象,原因是在創建DirectInputDevice對?
            象前需要該設備的GUID。?

            DirectInput庫為創建DirectInputDevice對象預定義了兩個GUID:GUID_SysKeyboard和?
            GUID_SysMouse。將兩者之一直接傳遞給CreateDevice函數,就會得到相應設備的?
            DirectInputDevice對象。?

            注意,令人感到奇怪的是缺少對游戲桿的預定義GUID。在Windows中,通常都有系統鍵盤?
            和系統鼠標,另一方面,系統本身并不使用游戲桿。可以安裝一個或者多個游戲桿,但系統?
            管理的范圍只限于驅動程序級。系統并為這些設備指定特殊的系統狀態,也不會在日常事務?
            中使用這些設備。因此,為游戲桿定義GUID對DirectInput來說是不合理的。?

            那么,如何才能找到與系統連接的游戲桿的GUID呢?要得到它們,必須要列舉設備。列舉?
            系統設備和性能在DirectX中相當普遍。要列舉系統中的輸入設備,需要使用EnumDevices?
            函數。EnumDevices是IdirectInput接口的一部分,如下定義:?

            HRESULT?EnumDevices(?
            DWORD?dwDevType,?
            LPDIENUMCALLBACK?lpCallback,?
            LPVOID?pvRef,?
            DWORD?dwFlags?
            );?

            注意此函數與Windows中其它列舉API相同,例如EnumWindows。第二個參數是一個回調函?
            數。第三個參數是程序中定義的32位值。第一個參數是想要列舉的設備類型,對游戲桿來?
            說,是DIDEVTYPE_JOYSTICK(全部的設備類型列在表4中)。最后一個參數是詳細描述想要?
            列舉的設備的標志。現在支持的標志是DIEDFL_ATTACHEDONLY和DIEDFL_ALLDEVICES(這兩?
            個標志是互斥獨占的),此外還有DIEDFL_FORCEFEEDBACK,此標志表示力反饋設備,能夠和?
            另兩個標志位或操作。?

            圖4:定義列舉的輸入設備:?
            以下定義的值可以傳遞給EnumDevices來選擇列舉哪種類型的輸入設備。另外也支持子類?
            型,見SDK中DIDEVICEINSTANCE結構的文檔。?
            值?說明?
            DIDEVTYPE_MOUSE?列舉鼠標設備?(標準、軌跡球等)?
            DIDEVTYPE_KEYBOARD?列舉鍵盤設備?(標準、鍵區等)?
            DIDEVTYPE_JOYSTICK?列舉游戲桿設備?(操縱桿、操縱輪、方向舵等)?
            DIDEVTYPE_DEVICE?列舉其它設備?


            當EnumDevices列舉系統中的輸入設備時,反復地調用回調函數。回調函數定義如下:?

            BOOL?CALLBACK?EnumProc(LPCDIDEVICEINSTANCE?lpddi,?LPVOID?pvRef)?;?

            因為回調函數是由用戶程序定義并傳遞給EnumDevices的,所以是調用CreateDevice的最?
            合適地方,直到創建了滿足需要的足夠DirectInputDevice對象為止。但是回調函數并非一?
            定要如此實現,可以簡單的將列舉設備的所有GUID保存在一個表中,在以后的代碼中使用。?

            回調函數接受兩個參數。第二個參數是程序定義的傳遞給EnumDevices的32位值。更重要?
            的是,第一個參數傳遞指向一個結構的指針,該結構包含關于能夠與列舉標準匹配的單個設?
            備的許多信息。這是一個DIDEVICEINSTANCE結構。此結構中最重要的一條信息是設備的?
            GUID,保存在結構的guidInstance成員中。?

            當程序中完全完成DirectInput有關的工作后,就應該調用IdirectInput接口的Release?
            成員。這就告訴DirectInput對象可以釋放自己了。在DirectX中,最好養成釋放對象的習?
            慣,從低層對象開始,到高層對象結束。正常情況下程序會作為清除或者關閉的例行公事的?
            一部分調用Release。這是使用每個DirectX組件的必要步驟,也是使用每個COM組件的必?
            要步驟。?

            現在已經用CreateDevice成員函數獲得了DirectInputDevice對象的一個接口,為開始處?
            理與系統連接的實際物理設備做好了準備。?
            使用DirectInputDevice對象?
            DirectInputDevice對象的每個實例都與系統中的特定設備相關。此對象提供了對系統硬件?
            更多的控制和能力,從而使DirectX的允諾實現。下面討論擁有了DirectInputDevice對象?
            后下一步干什么。?

            擁有了IdirectInputDevice接口的一個接口指針,現在干什么?首先,設置設備的數據格?
            式。通過調用SetDataFormat來完成,該函數是一個接口成員函數。設置數據格式包括無數?
            可能的決定,包括軸信息、相對或絕對坐標信息、等等。所有這些細節通過一個叫作?
            DIDATAFORMAT的結構傳遞給此函數。實際上,SetDataFormat唯一的參數就是指向此結構的?
            指針。?

            填寫這個結構的細節會使人發憷。值得感謝的是這一工作并不是必須的,因為DirectInput?
            已經定義了幾個DIDATAFORMAT結構變量,可以用于比較普通的輸入設備:c_dfDIKeyboard,?
            c_dfDIMouse,?c_dfDIJoystick,?和c_dfDIJoystick2。為普通的力反饋游戲桿設置數據格?
            式,可以使用下面的調用形式:?

            lpdid->SetDataFormat(?&c_dfDIJoystick?)?;?
            在此例中,lpdid是指向IdirectInputDevice接口的指針。?

            設置完設備對象的數據格式后,就需要設置設備的協作級別。因為協作級別在整個DirectX?
            中很常見,所以這里要做一下說明。大多數直接處理系統硬件的DirectX對象在接口的成員?
            中都有一個叫作SetCooperativeLevel函數。這個函數很重要,因為它定義了程序操縱與系?
            統中其它進程有關的硬件的控制級別。同其它DirectX對象一樣,只有設置了協作級別才能?
            使DirectInputDevice對象工作。要理解協作級別,就需要熟悉Acquire函數。調用此函數?
            是為了獲得對物理設備的實際訪問(不要和邏輯上的DirectInputDevice對象混了)。相反?
            的,Unacquire函數釋放對物理設備的訪問。?

            下面是函數SetCooperativeLevel的定義:?

            HRESULT?SetCooperativeLevel(?
            HWND?hwnd,?
            DWORD?dwFlags?
            );?

            hwnd是程序的主窗口。標志是下面一些值的或操作的結合:?DISCL_BACKGROUND,?
            DISCL_FOREGROUND,?DISCL_EXCLUSIVE,?DISCL_?NONEXCLUSIVE。?

            如果標志參數中或上了DISCL_EXCLUSIVE,則當獲得設備后本程序就成為唯一允許訪問該物?
            理設備的進程。另一方面,如果選擇了DISCL_NONEXCLUSIVE,那么系統中可以有多個進程?
            同時協作獲得和使用該設備。如果或上了DISCL_BACKGROUND,程序將不會失去物理設備。?
            然而,象Ctrl+Alt+Del組合鍵被按下這樣的系統事件仍然能夠隱含地"unacquire"程序中?
            的設備。如果使用了DISCL_?FOREGROUND,當不是活動窗口時,程序將會自動釋放物理設備。?
            這就是將程序主窗口句柄傳遞給SetCooperativeLevel的意義。DirectX根據窗口是否是系?
            統當前活動窗口自動調整設備共享。?

            那么所有這些值的意義是什么呢?下面舉個例子說明。如果力反饋游戲桿的協作模式是?
            DISCL_FOREGROUND?|?DISCL_EXCLUSIVE,那么只要程序處于活動狀態,就能夠從游戲桿讀數?
            據并播放力反饋效果(力反饋需要exclusive-level協作)。只要用戶一選擇其它程序,程?
            序就失去對物理設備的控制,新激活的程序就能夠訪問該設備。這意味著在調試程序時,如?
            果切換到調試器窗口,程序就會因為窗口變為非活動的而失去對游戲桿的控制。?

            如果將同一游戲桿的協作級別設為DISCL_BACKGROUND?|?DISCL_EXCLUSIVE將會是什么情況?
            呢?程序將會所有時間都能訪問游戲桿,不管窗口的狀態。但是現在系統中其它進程就不能?
            獲得游戲桿,除非程序釋放了游戲桿,不管用戶在做什么!?

            非常明顯,在正式發布的產品中應該使用DISCL_FOREGROUND?|?DISCL_EXCLUSIVE,而在調?
            試版本中應該使用DISCL_BACKGROUND|DISCL_EXCLUSIVE。但是也不總是這樣選擇。例如,?
            如果設備是系統鍵盤,那么DirectInputDevice想獨占使用而調用SetCooperativeLevel將?
            會失敗。這是因為操作系統想要允許用戶自由地從一個程序切換到另一個程序。類似的,?
            DirectInputDevice不會允許以協作級別DISCL_BACKGROUND|DISCL_EXCLUSIVE請求系統鼠?
            標。Windows不希望一個程序能夠完全將用戶與操作系統的聯系切斷。?

            在能夠從物理設備讀取信息或向物理設備發送信息之前,必須要用Acquire獲得設備。在臨?
            時或永久結束設備使用時要明確地使用Unacquire函數釋放設備。但Unacquire并不是失去?
            設備控制的唯一方法。?

            如果設置協作級別時使用DISCL_FOREGROUND標志,那么程序的主窗口不再是系統中的活動?
            窗口時設備將被明確釋放。這就是說,在程序調用Acquire和實際試圖從設備讀取信息之間,?
            能夠失去對設備的占有。所以需要檢查返回值來捕捉這樣的錯誤,并準備好在任何時間重新?
            獲得該設備。?

            關于Acquire和Unacquire的決定性要點:當程序獲得獨占協作級別的設備時,DirectX擁?
            有該設備。例如,如果鼠標被DirectX(獨占)獲得,那么程序窗口中的按鈕就不會對鼠標?
            做出響應。這就是說,如果想讓Windows對設備響應,就應該釋放該設備。換句話說,如果?
            不想讓DirectInput從設備中讀取數據,就調用Unacquire。?

            設置完設備的協作級別后,接著應該為設備配置其它設置。獲得了設備后,接著就應該開始?
            使用GetDeviceState函數輪流檢測輸入的數據。當完成與設備對象的操作后,調用Unacquire?
            釋放DirectInputDevice對象。設備與設備之間存在細節上的差別;下面講解游戲桿和鍵盤,?
            應該能為從其它設備讀取輸入提供足夠的基礎知識。?
            鍵盤?
            鍵盤是到目前為止最容易讀取的設備。實際上,設置完數據格式、協作級別、獲得設備以后,?
            就可以讀取鍵盤狀態了。讀取鍵盤狀態要使用IdirectInputDevice接口的GetDeviceState?
            成員。GetDeviceState用關于物理設備的狀態信息組裝一個結構,所組裝結構的類型由前?
            面對SetDataFormat的調用決定。對鍵盤來說,此數據結構是一個簡單的256個字節組成的?
            數組。每個字節對應于鍵盤上的一個鍵,如果某個鍵按下,相應字節的高位就被設置。?

            DirectInput定義了一套以DIK_XXX為前綴的常量,這些常量可以用來索引字節數組以找到?
            關于特定鍵的數據。例如,如果要檢查右Shif鍵當前是否按下,可以使用DIK_RSHIFT定義:?

            GetDeviceState(256,(LPVOID)?cKeyboardData)?;?
            if(cKeyboardData[DIK_?RSHIFT]&0x80)?
            DoWhatever()?;?

            CKeyboardData是256個字節的緩沖區。幾乎就是這么簡單,但是要記住,不管GetDeviceState?
            在何時返回DIERR_INPUTLOST,就必須使用Acquire獲得設備。這種情況發生在每次用戶從?
            程序切換離開的時候。?

            還有一點很重要,就是能夠請求DirectInput緩沖鍵盤信息。這要求提供一個緩沖區并使用?
            SetProperty為設備設置緩沖區大小。在本文中沒有篇幅討論這一技術,但這一技術在程序?
            不能相當頻繁的檢查鍵盤狀態時非常有用。用戶有可能在程序中兩次GetDeviceState調用?
            之間按下又松開了一個鍵,如果DirectInput不緩沖鍵盤數據的化,這種擊鍵動作就丟失了。?

            游戲桿?
            游戲桿非常好玩。與其好聽的名稱(Joystick--原意為歡樂桿)相符,這種設備為游戲體?
            驗添加了許多樂趣,同時也為程序員的體驗添加了一些東西。正常情況下,通過調用?
            IdirectInput接口的CreateDevice成員得到IdirectInputDevice接口(和對象),這對游?
            戲桿也適用。?

            但是開發人員都希望立即將接口升級到IDirectInputDevice2,那么可以象下面這樣使用?
            QueryInterface調用請求CreateDevice返回新的接口:?

            hr?=?lpDIDeviceJoystickTemp->QueryInterface(?IID_IDirectInputDevice2,?
            (void?**)?&g_lpDIDeviceJoystick);?

            如果成功,就可以釋放原來的接口,開始使用漂亮的新IDirectInputDevice2接口。但是為?
            什么要這么做?IDirectInputDevice2接口提供IdirectInputDevice的所有功能,而且還?
            有另外兩個重要特性:支持查詢設備和支持力反饋設備。?

            其次,需要設置上的一些考慮。還記得SetDataFormat定義了GetDeviceState返回的數據?
            的類型。對于游戲桿設備,使用c_dfDIJoystick或c_dfDIJoystick2兩個預定義變量之一,?
            將返回數據的類型設置為DIJOYSTATE或DIJOYSTATE2結構。選擇哪種主要取決于要使用游?
            戲桿哪種類型的特性。瀏覽這些結構中的成員應該對弄清這個問題有幫助。?

            同所有輸入設備一樣,要為游戲桿設置數據格式和協作級別。游戲桿往往比鍵盤需要更多一?
            點注意。這是因為現在還幾乎沒有功能完美的游戲桿,所以程序應該檢查以確保控制的設備?
            能滿足要求。如果不能,就調整要求或者提醒用戶游戲桿太落后!設備的能力可以并且應該?
            調用IdirectInputDevice接口的成員函數GetCapabilities探測。?

            這就引出了適用于所有DirectX組件的另一個討論點。DirectX為多種設備提供廣泛的支持。?
            軟件開發環境和使用環境可能有很大差別,不同的計算機支持不同水平的DirectX功能。編?
            寫好使用DirectX的軟件,需要檢查硬件的能力。最差的情況下,如果某個功能不支持,可?
            以退出程序。最好的情況當然是程序能夠聰明地根據缺少的特性調整本身的需求。?

            在開始從設備得到輸入之前,需要設置設備的特性。這些特性包括象返回值的范圍、游戲桿?
            的中心點等此類的細節。這一工作由函數SetProperty完成,相當復雜。?

            SetProperty設置設備的一個特性。首先,必須使用關于要改變的設置的一些信息填寫一個?
            數據結構。請參考Platform?SDK中的文檔,得到所有數據結構。每個結構都以一個?
            DIPROPHEADER結構開始,此結構中填寫描述要改變的設置的信息。然后,用特定于所改變?
            的設置的數據填寫結構中剩余的部分。最后,調用SetProperty,參數是GUID和指向結構?
            中DIPROPHEADER部分的指針。下面的代碼片段將游戲桿的垂直范圍設置為-100到100:?

            DIPROPRANGE?dipRange?;?
            dipRange.diph.dwSize?=?sizeof(dipRange);?dipRange.diph.dwHeaderSize?=?
            sizeof(dipRange.diph);?dipRange.diph.dwObj?=?DIJOFS_Y;?
            dipRange.diph.dwHow?=?DIPH_BYOFFSET;?
            dipRange.lMin?=?-100;?
            dipRange.lMax?=?+100;?
            g_lpDIDeviceJoystick->SetProperty(?DIPROP_RANGE,?&dipRange.diph)?;?

            此結構中最難懂的部分是diph.dwObj和diph.dwHow。diph.dwHow描述diph.dwObj中保存?
            何種信息。diph.dwObj實際描述哪個屬性被設置。大多數情況下,diph.dwHow的值是?
            DIPH_BYOFFSET,diph.dwObj的值是傳遞給SetDataFormat的結構中一個預定義的偏移。?

            應該指出能夠列舉設備的對象,包括按鈕和其它特點。這一工作由EnumObjects函數完成。?
            這樣做時,應該提供一個對象標志符。將此標志符傳遞給diph.dwObj成員,將diph.dwHow?
            成員填寫為DIPH_BYID。?

            在從設備讀取數據之前,至少要為設備的X和Y坐標軸設置最小和最大值。設置好設備屬性?
            后,就可以獲得設備并開始從設備獲得數據。從游戲桿獲取數據與從鍵盤或鼠標獲取數據不?
            同,因為游戲桿是查詢設備。?

            鍵盤和鼠標會引發硬件中斷,由系統中的驅動程序處理,并用來更新通過調用?
            GetDeviceState由DirectInput返回的數據。查詢設備(如大多數游戲桿)不產生硬件中?
            斷,因此,DirectInput必須被告知從設備獲取狀態信息。這一工作通過調用?
            IDirectInputDevice2接口的Poll成員函數完成。此時也是檢查?設備是否需要重新獲得的?
            適當時機。設備被成功查詢后,就可以調用GetDeviceState獲取狀態信息。?

            如果調用SetDataFormat時使用c_dfDIJoystick變量,那么GetDeviceState將用游戲桿當?
            前的狀態信息填充一個DIJOYSTATE結構。此結構的內容主要取決于物理設備的特性和?
            SetProperty的設置。例如,如果結構中的lY成員等于-50,并且Y軸的范圍設置為-100到?
            100,那么就是說游戲桿在垂直方向上處于中心和最頂端的中間。程序中應該確保設備的范?
            圍設置為能合理滿足需求的值。為了從游戲桿設備中獲取數據,程序應該定期查詢設備。?
            使用DirectInputEffect?
            首先,應該解釋一些力反饋技術。力反饋設備是能夠產生用戶可以感覺到的力的設備,這些?
            力叫作效果,例如顛簸效果或者持續的將操縱桿推向右上方的力。這些效果是“播放?
            ”出來的,效果由程序控制播放,或者對函數調用響應,或者對用戶按鍵自動反應。?

            DirectInput目前支持大約一打不同的效果類型(見表5)。這些效果的范圍從完全由程序控?
            制的低級持續力效果,到由DirectInput或設備自己控制的高級傾斜或波動效果。效果有四?
            種基本類型:持續力、傾斜效果、周期效果和條件。持續力是單一方向上不改變強度的力。?
            傾斜效果是強度隨時間線性變化的持續的力。周期效果是沿著給定的軸重復變化,其量級或?
            者力的強度由周期效果定義。條件是對用戶與游戲桿的交互作用做出響應的效果。這種效果?
            可能是象一根彈簧,操縱桿向某個方向推得越遠,反彈力就越強。?

            表5:DirectInput效果的類型?
            GUID?說明?使用方法注解?
            GUID_ConstantForce?固定強度、特定方向的持續拉力。?使用DICONSTANT力結構作為?
            DIEFFECT結構的一部分實現持續力。?
            GUID_CustomForce?一序列持續力下傳到設備,按順序播放。?DICUSTOMFORCE結構被用來定?
            義力。?
            GUID_Damper?隨沿坐標軸的移動增加的條件效果。?實現這種效果的特定類型結構是?
            DICONDITION結構。條件效果通常不支持包。?
            GUID_Friction?阻礙沿坐標軸移動的條件效果。?實現這種效果的特定類型結構是?
            DICONDITION結構。條件效果通常不支持包。?
            GUID_Inertia?隨沿坐標軸移動的加速度增加的條件效果。?實現這種效果的特定類型結構是?
            DICONDITION結構。條件效果通常不支持包。?
            GUID_RampForce?特定方向上大小線性增加或減小的拉力。?DIRAMPFORCE結構被用來作為?
            DIEFFECT結構中的類型相關部分。?
            GUID_SawtoothDown?力瞬間達到最大然后線性減小到最小的周期效果。?需要的特定類型結?
            構是DIPERIODIC結構。?
            GUID_SawtoothUp?力從最小線性增加到最大然后瞬間降到最小的周期效果?需要的特定類型?
            結構是DIPERIODIC結構。?
            GUID_Sine?力正弦變化的周期效果。?需要的特定類型結構是DIPERIODIC結構。?
            GUID_Spring?力隨到某個中點的相對距離而增大的條件效果。?實現這種效果的特定類型結?
            構是DICONDITION結構。條件效果通常不支持包。?
            GUID_Square?力瞬時在最大與最小之間轉變的周期效果。?需要的特定類型結構是DIPERIODIC?
            結構。?
            GUID_Triangle?力在最大與最小之間線性變化的周期效果。?需要的特定類型結構是?
            DIPERIODIC結構。?


            下面所有與力反饋游戲桿有關的工作都是針對Microsoft?SideWinder?Force?Feedback?Pro?
            游戲桿,這就是說,本文中的某些細節對其它設備可能多少會產生一些問題。?

            在創建力反饋效果以前先獲得設備是一個不錯的想法。雖然這不是必須的,但是在效果能夠?
            被下傳到設備前必須要獲得設備。這一點對于播放對用戶按下按鈕做出反應的力效果尤其重?
            要。?

            要創建效果,首先要為每個打算使用的效果創建DirectInputEffect對象的實例。這一工作?
            通過調用IDirectInputDevice2接口的CreateEffect成員函數完成。此函數需要效果的?
            GUID,以及指向DIEFFECT結構的指針,該結構中填寫的是效果的細節。最后,CreateEffect?
            返回一個指向IdirectInputEffect接口的指針,該指針的地址是CreateEffect的一個參數。?
            這個調用的核心部分集中在DIEFFECT結構的填充。?

            DIEFFECT結構如下定義:?

            typedef?struct?{?
            DWORD?dwSize;?
            DWORD?dwFlags;?
            DWORD?dwDuration;?
            DWORD?dwSamplePeriod;?
            DWORD?dwGain;?
            DWORD?dwTriggerButton;?
            DWORD?dwTriggerRepeatInterval;?
            DWORD?cAxes;?LPDWORD?rgdwAxes;?
            LPLONG?rglDirection;?
            LPDIENVELOPE?lpEnvelope;?
            DWORD?cbTypeSpecificParams;?
            LPVOID?lpvTypeSpecificParams;?
            }?DIEFFECT,?*LPDIEFFECT;?

            dwSize成員是此結構的字節數。DwFlags指出效果使用的坐標類型,以及是使用偏移方法還?
            是ID方法描述按鈕(就向前面說明的SetProperty)。通常情況下,可以設置為?
            DIEFF_CARTESIAN|DIEFF_OBJECTOFFSETS,即按鈕采用偏移描述,坐標使用XYZ坐標形式。?

            DwDuration說明效果播放多少毫秒。注意dwDuration可以設為INFINITE。DwSamplePeriod?
            說明效果播放一個周期花費多少毫秒。不同設備支持不同的周期。實際中,SideWinder游?
            戲桿支持的周期不大于1秒,不小于1/80秒。DwGain可以看作效果的主要量,因為它說明?
            效果多么有力。此值的范圍是0到10000。?

            DwTriggerButton和dwTriggerRepeatInterval用來設置觸發效果播放的按鈕,以及重復頻?
            率。當然,可以通過將dwTriggerButton的值設置為DIEB_NOTRIGGER來將效果設置為與按?
            鈕無關。否則,dwFlags定義通過ID還是偏移方式描述按鈕。因為偏移方式不需要調用?
            EnumObjects,所以一般可以將值指定為DIJOFS_?BUTTON0和DIJOFS_BUTTON1。?

            CAxes成員說明效果將影響幾個軸。RgdwAxes指向一個描述所包含的軸的DWORD數組,數組?
            中每個軸是一個成員。同按鈕一樣,軸也是用偏移或者ID來指明。一般的偏移值包括DIJOFS_X?
            和DIJOFS_Y。?

            同樣,rglDirection成員指向一個long型數組,每個軸是一個成員。在笛卡兒坐標中,?
            (Y=-1,X=1)與(Y=-10,X=10)描述的是同一個方向。這就是說,如果想得到一個不是45?
            度整數倍方向上的斜的力,就應該調整兩個值的相對大小。例如,(Y=-10,X=1)描述與上?
            面例子在同一象限的方向,但卻明顯靠近Y軸。?

            效果也可以有描述它們的包。填充一個DIENVELOPE結構,并將其地址填寫到lpEnvelope成?
            員就可以完成。包可以在一段時間內影響效果的數量或力量。其中,起動水平是效果的開始?
            變化點,啟動時間說明效果達到力量保持階段花費多少毫秒。衰減水平是效果在包最后達到?
            的水平,衰減時間是衰減用掉了多少毫秒。包可以用來制造初始狀態較強,然后慢慢衰減的?
            力效果。圖1中描繪了包如何改變效果。?


            DIEFFECT結構的最后兩個成員是cbTypeSpecificParams和lpvTypeSpecificParams。它們?
            保存特定于所創建效果類型的結構的字節數和地址。特定類型的效果使用何種結構的信息見?
            表5。?

            填寫完這個結構并調用CreateEffect后,就會獲得指向IdirectInputEffect接口的指針,?
            現在可以使用此接口播放效果,改變效果等。如果沒有將效果聯系到按鈕,就必須用?
            IdirectInputEffect接口的Start和Stop成員播放和停止效果。如果效果與按鈕關聯,那?
            么在創建時下傳到設備;否則,效果在播放時自動下傳到設備。如果程序必須重新獲得設備,?
            那么所有與按鈕相關的效果必須通過明確的調用Download成員才能下傳到設備。?

            效果能夠用Unload成員卸載,也能夠通過向SetParameters成員函數傳遞新的DIEFFECT結?
            構重新設置參數。當程序用完效果后,必須調用接口的Release成員。?
            ?

            posted on 2006-06-20 16:21 楊粼波 閱讀(737) 評論(0)  編輯 收藏 引用 所屬分類: 文章收藏

            久久w5ww成w人免费| 久久综合给久久狠狠97色| AAA级久久久精品无码区| 无码任你躁久久久久久| 久久精品国产亚洲av水果派 | 久久国产精品偷99| 久久国产精品99国产精| 国产精品免费看久久久香蕉| 国内精品综合久久久40p| 一本大道久久香蕉成人网| 久久精品国产清自在天天线| 亚洲午夜久久久久久久久久| 久久99精品国产99久久6| 国产毛片久久久久久国产毛片| 色天使久久综合网天天| 亚洲级αV无码毛片久久精品| 久久频这里精品99香蕉久| 亚洲色欲久久久久综合网| 99999久久久久久亚洲| 91久久香蕉国产熟女线看| 99久久精品国产一区二区| 亚洲AV无码1区2区久久| 伊人久久大香线蕉综合5g| 国产高潮国产高潮久久久91| 久久男人Av资源网站无码软件| 久久久黄色大片| 亚洲国产成人久久综合野外| 国产高潮国产高潮久久久91| 亚洲一区中文字幕久久| 97r久久精品国产99国产精| 久久久久亚洲AV成人片| 亚洲精品国产美女久久久| 久久香综合精品久久伊人| 伊人久久大香线蕉综合网站| 久久亚洲国产成人精品无码区| 精品久久久中文字幕人妻| 久久91综合国产91久久精品| 日日狠狠久久偷偷色综合0 | 久久AV无码精品人妻糸列| 久久天天婷婷五月俺也去| 亚洲精品综合久久|