「DirectX 11」即將發佈 遊戲界將再度大地震

剛才同學丟給我的震撼彈
市面上才剛有一些 DX 10 的遊戲出現,現在又殺出 DX 11
無疑又是給程式設計師們一刀 Critical !

轉載遊戲基地的新聞「『DirectX 11』即將發佈 遊戲界將再度大地震


    DirectX 從發展開始至今,已有好 13 年的歷史。DirectX 主要是以 DirectX Graphics(DirectDraw、Direct3D)、DirectInput、DirectPlay、DirectMusic、DirectX Media、DirectX Media Objects、DirectSetup所構成,這些構成的重要元件是影響遊戲開發的許多重要因素。

     透過 DirectX 的進步,玩家從大約 DirectX 3.0 左右版本開始時,就會發現安裝遊戲時,遊戲說明書與安裝程式都開始要求一同安裝這支程式。演變至今,如今將在 2008 年七月正式發表「DirectX 11」,這意謂著玩家在遊戲上的享受將又會有更大一個層次的變動。

     現今世面上還是以 2002 年所推出的「DirectX 9」所製成的遊戲為主,然而在少數講求逼真的特效畫面遊戲中,才剛開始漸漸有遊戲公司使用「DirectX 10」來開發遊戲。這才剛起步,馬上又即將推出「DirectX 11」,推出這麼快的結果就是舊有的遊戲被淘汰的速度將會加快,而新起步的遊戲畫面、聲光效果等都將大幅提升,大幅提升的代價就是玩家的硬體有可能又要大 換血一次。

     無論如何,「DirectX 11」大約近期就會推出,此次將會支援至 Shader model 5.0,玩家可以試著期待它將帶來什麼樣的改變。(不禁讓筆者擔心《暗黑破壞神3》是以 DirectX 9 所開發而成,面對此事件是否會有什麼變動呢?)


嗯哼~
慶幸,我還沒開始探索 DX 10
可怕,未來似乎會有許多變動
前陣子也看到 Vista 會被 Windows 7 所取代,現在又殺出 DX 11

老實說,既期待又害怕 XD
已經在業界工作的可能狂冒冷汗吧

今年真是太有趣了!

–End

DXUT – CGrowableArray

CGrowableArray 是 DXUT 裡面的其中一個類別
嗯~就是一個簡單的動態陣列
拜辜狗的時候看到這類別有一點小bug

以下為原始code:

 CGrowableArray( const CGrowableArray<TYPE>& a )
 {
     for( int i=0; i < a.m_nSize; i++ )
         Add( a.m_pData[i] );
 }


CGrowableArray 的複製建構元沒有對成員變數做初始化的動作
所以要修復這個bug只需要在加上初始化即可

 CGrowableArray( const CGrowableArray<TYPE>& a ) : m_nMaxSize(0), m_nSize(0), m_pData(0)
 {
     for( int i=0; i < a.m_nSize; i++ )
         Add( a.m_pData[i] );
 }


OK~這樣就沒問題了!
目前我是使用 2006 Aug版本,這錯誤還沒修正
幸好在碰上錯誤之前看到,不然八成又會瘋狂了XD
不知道哪一版有做修正,祝各位code愉快~

來源: Might it be a BUG within DXUT?

–End

Direct3D Sprites

最近開始著手雛型版的ARPG
重新弄一個以DXUT為基礎的小引擎
在 DirtecX 裡面負責 2D 圖像處理的DXSprites,就順便整理一下

DXSprites 的介面是 ID3DXSprite
宣告於 d3dx9.h 裡,並且需要連結 d3dx9d.lib or d3dx9.lib ,前者Debug用後者Release用

同樣的,需要向 DX 取得 Sprite 物件,利用 D3DXCreateSprite

HRESULT D3DXCreateSprite(LPDIRECT3DDEVICE9 pDevice, LPD3DXSPRITE *ppSprite);

    pDevice – D3D 設備的指標
    ppSprite – 輸出用的Sprite介面指標

OK~取得之後,就可以進行 Render 的動作了!

和 D3D Device 一樣,Sprite 的繪製動作需要在 Begin & End 之間

HRESULT ID3DXSprite::Begin(DWORD Flags);
HRESULT ID3DXSprite::End( );

Begin 所需要的 flags 請參閱SDK的說明
HRESULT ID3DXSprite::Draw(LPDIRECT3DTEXTURE9 pSrcTexture,
    CONST RECT *pSrcRect,
    D3DXVECTOR3 *center,
    CONST D3DVECTOR3 *pTranslation,
    D3DCOLOR Color );

    pSrcTexture – 將要繪製的 IDirect3DTexture 指標
   
pSrcRect – 繪製該 Texture 的矩形區塊,若是 NULL ,則設為整張圖片
   
center – 繪製的起始點,若是 NULL ,則設為左上角 (0, 0, 0)
    pTranslation – 位移,若是 NULL ,則設為螢幕左上角 (0, 0, 0)
    Color – 輸出的顏色量,ARPG

OK~最陽春的也很夠用的方式就只需要這些了!
一小段範例:

 // 假設已經有了一個D3D設備( pd3dDevice )以及一個紋理( pTex )
 ID3DXSprite * sprite = NULL;

 // 取得Sprite
If ( SUCCEEDED( D3DXCreateSprite( pd3dDevice, &sprite ) )
{
      // created OK
}

 //
 // …
 //
 // 設定要繪製的position ( 10, 50 )
 D3DXVECTOR3 pos( 10.0f, 50.0f, 0.0f );

 // Render
 if( SUCCEEDED( pd3dDevice->BeginScene( ) ) )
 {
      // 只開啟Alpha混合
      pd3dSprite->Begin( D3DXSPRITE_ALPHABLEND );
      // 順便將繪製起點移到 ( 0, 10 )
      pd3dSprite->Draw( pTex, NULL, &D3DXVECTOR3( 0.0f, 10.0f, 0.0f ), &pos, 0xFFFFFFFF)
      pd3dSprite->End( );

      // 關閉場景
      pd3dDevice->EndScene( );
 }

先這樣@_@
晚點再補 SetTransform 的部份~

— End

DirectSound 掰~?!

今天在爬OpenAL的文章時看到…
文章連結
看一下日期,是五月前的文章了
我對這世界還真不熟啊 ||Orz
那些廠商應該整個囧掉吧?
反正目前還不打算用DSound,就隨它去吧

繼續步上AL之路…(轉身)
話說,1.1版的OpenAL幾乎沒文章是怎樣

DirectX – Acquire() 與 E_ACCESSDENIED 之章

啊哈哈~~
基本上在解決之前接近瘋狂狀態了

話說今天開始把 DirectInput 改寫成類別
在最後測試的時候,在 Acquire() 的地方出錯
回傳了 E_ACCESSDENIED 给我。
經過交叉測試,最後把先前的成功範例拿出來 compiler
還是給了我 E_ACCESSDENIED…

在暴走了許久後,終於在網路海海之中找到解決方案!

引用 上一章 的範例片段:

    m_pDIKeyboardDevice->Acquire();

初始化時,都會加上 FAILED() 檢查是否取得成功
現在改成不檢查了!
不然就是要使用的時候才測試是否取得囉!

嘿~這就是解決方案XD(要說是逃避方案也形吧!)

目前用來似乎真的可以這樣做,就暫定為正式解決的方案吧!
CSDN大好啊!一堆問題都有解答

◎參考:
    http://tag.csdn.net/Article/d15ea0e3-ffc2-48bb-9106-72ace270e5f0.html
    http://blog.csdn.net/Garfield/archive/2005/02/21/295317.aspx

DirectX – 輸入之章

DirectInput 應該是 DirectX 裡面最簡單的介面吧
相較於 Win32 的基本輸入,不用通過 windows 取得,所以相對較快速。

網站上的說法:

    * It enables an application to retrieve data from input devices even when the application is in the background
    * It provides full support for any type of input device, as well as for force feedback
    * Through action mapping, applications can retrieve input data without needing to know what kind of device is being used to generate it.

總而言之,就是有好處才會有人用咩~(不負責宣言)
對了,因為 DirectInput  從 8 版之後就沒更新了,所以底下都使用 8 版,而非 9 版唷!


DirectInput 也是 COM 物件,所以先來介紹主要的介面~

 物件  說明
 IDirectInput8  DirectInput 最主要的介面,其他相關介面從這可取得。
 IDirectInputDevice8  設備的介面,每種設備都有各自的介面。
 IDirectInputEffect  動力回饋(force feedback)介面,某些滑鼠或搖桿會用到。

首先,先引入 dinput.h 並連結 dinput8.lib 和 dxguid.lib (globally unique identifier for DX)

    #include <dinput.h>

接著宣告主要介面和設備介面的指標

    // 主要介面的指標
    LPDIRECTINPUT8 m_pDInput;

    // 鍵盤界面的指標,如需要滑鼠或搖桿,需要再另外增加!
    LPDIRECTINPUTDEVICE8 m_pDIKeyboardDevice;

接著創造主要介面

    DirectInput8Create(inst, DIRECTINPUT_VERSION,
                    IID_IDirectInput8, (void**)&
m_pDInput, NULL);

第一個參數需要視窗的 instance。
第二個參數是 DirectInput 的版本。
第三格參數是我們需要創造的介面種類,來自
dxguid.lib
第四個參數是我們的介面指標。
第五個參數是進階使用,通常設為 NULL。

接著創造鍵盤介面

    m_pDInput->CreateDevice(GUID_SysKeyboard, &m_pDIKeyboardDevice, NULL);

第一個參數是我們要創造的設備種類,鍵盤(GUID_SysKeyboard)、滑鼠(GUID_SysMouse)、搖桿(GUID_Joystick)。
第二個參數是我們的設備介面指標。
第三個是進階使用,通常設為 NULL。

接著設定設備的資料結構

    m_pDIKeyboardDevice->SetDataFormat( &c_dfDIKeyboard );

唯一的參數是我們需要的資料格式,鍵盤(c_dfDIKeyboard)、滑鼠(c_dfDIMouse)、搖桿(c_dfDIJoystick)。

接著設定合作等級

    m_pDIKeyboardDevice->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);

第一個參數需要程式的視窗代碼。
第二個參數是合作等級。

合作等即可分兩類,是否獨占與前背景讀取。

 等級  說明
 DISCL_EXCLUSIVE  獨占,就只能自己用啦!
 DISCL_NONEXCLUSIVE  共同使用,不會干擾到其他程式。
 DISCL_FOREGROUND  前景讀取,需要是(Focus)情況下才能讀取資料,失焦時會自動變成無法讀取。
 DISCL_BACKGROUND  不管在縮小或其他程式中,一樣可讀取資料。
 DISCL_NOWINKEY  取消 Windows 商標按鍵的作用。

OK!都準備完成了,接下來開始使用吧!



使用鍵盤設備

第一件事情就是先取得設備

    m_pDIKeyboar
dDevice
->Acquire();

並不需要每次讀取資料就取得一次,除非第一次或喪失該設備(縮小或Alt-Tab之類)才須取得。

我們需要一個 256 Byte 的緩衝區,使用 GetDeviceState 來接收鍵盤資訊

    BYTE keys[256];

    // 使用前先初使化緩衝區
    ZeroMemory(keys, sizeof(keys) );
   
m_pDIKeyboardDevice->GetDeviceState( sizeof(keys), keys );

和 Win32 一樣,每個按鍵都有一個巨集,在  DirectInput 裡面是以 DIK_ 開頭的。
例如按鍵 A 定義為 DIK_A,Esc 鍵則定義為 DIK_ESCAPE。

偵測 Esc 被按下

    if (keys[DIK_ESCAPE] & 0x80)
        //  Esc 被按下

偵測 X 被按下

    if (keys[DIK_X] & 0x80)
        // x 被按下

最後,使用完之後可別忘記要釋放他們唷!

    if (m_pDIKeyboardDevice)
    {
       
m_pDIKeyboardDevice->Unacquire();
       
m_pDIKeyboardDevice->Release();
    }

    if (m_pDInput)
       
m_pDInput->Release();



如何偵測設備喪失!

當我們在取得設備資訊時,如果該設備 lost 掉,會回傳 DIERR_INPUTLOST 的錯誤碼。
利用回圈檢查,直到取得為止才繼續執行。

    hr = m_pDIKeyboardDevice->GetDeviceState( sizeof(keys), keys );

    if (FAILED(hr))
    {
        hr = m_pDIKeyboardDevice->Acquire();

        while( hr == DIERR_INPUTLOST )
        {
            hr = m_pDIKeyboardDevice->Acquire();
        }

        // 成功取得後再取得一次資訊
        m_pDIKeyboardDevice->GetDeviceState( sizeof(keys), keys );
    }



使用滑鼠設備

前置作業都差不多,參數不同而已,不贅述囉~

    m_pDInput->CreateDevice(GUID_SysMouse, &m_pDIMouseDevice, NUL
L
);
   
m_pDIMouseDevice->SetDataFormat(&c_dfDIMouse2);
   
m_pDIMouseDevice->SetCooperativeLevel(hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);

如同鍵盤一樣,需要一塊緩衝區來使用 GetDeviceState 讀取資料

    DIMOUSESTATE2 m_mouseState;
    ZeroMemory( &m_mouseState, sizeof(m_mouseState) );
   
m_pDIMouseDevice->GetDeviceState( sizeof(DIMOUSESTATE2), &m_mouseState );

同樣要檢查是否回傳 DIERR_INPUTLOST 嘿!
注意,這裏使用 c_dfDIMouse2 和  DIMOUSESTATE2 ,是擁有八顆鍵的滑鼠(應該…)

DIMOUSESTATE2  的資料結構:

    typedef struct _DIMOUSESTATE2 {
        LONG    lX;   // X
的偏移量
        LONG    lY;   // Y
的偏移量
        LONG    lZ;    // Z軸的偏移量
        BYTE    rgbButtons[8];   // 每個按鈕的狀態
    } DIMOUSESTATE2, *LPDIMOUSESTATE2;

記住,是偏移量,而不是位置
所以通常在初始化時會先利用 GetCursorPos 或者 WM_MOUSEMOVE 時取得一開始的位置
然後在隨時更新座標即可!

    // 宣告兩個變數儲存位置
    long g_MouseXPos = 0;
    long g_MouseYPos = 0;

    // 遊戲迴圈
    void Run()
    {
       // 讀取滑鼠資料

       // 更新滑鼠的絕對座標
      
g_MouseXPos += m_mouseState.lX;
       g_MouseYPos += m_mouseState.lY;

       // 其他程式碼
    }

檢查某按鈕狀態

    if (m_mouseState.rgbButtons[0] & 0x80)
       // 左鍵(0)被按下

最後,還是別忘記用完要釋放他們唷!



◎參考:
       http://www.toymaker.info/
       2D/3D RPG角色扮演遊戲程式設計 – 使用DirectX / Jim Adams著
   
當然,還有一個 搖桿設備 的部份,不過目前還用不到,而且前置動作很雜,以後用到在補上吧XD