游戏DX接管的研究

来源:互联网 发布:mac照片怎么导出 编辑:程序博客网 时间:2024/04/25 01:36

这几天研究了一下DX,目标是DX3D , DXDraw , DXInput。

  • DX3D :

      DX3D 首先通过函数Direct3DCreate8创建一个D3D对象,这个对象是一个DLL导出的函数,函数返回LPDIRECT3D8对象。这个对象是个COM对象。这下有趣的东西来了。C++编译器对COM对象编译的结果如下:

00401068  |.  50            push    eax
00401069  |.  6A 00         push    0
0040106B  |.  8B0D 58C04100 mov     ecx, dword ptr [g_pD3D]
00401071  |.  8B11          mov     edx, dword ptr [ecx]
00401073  |.  A1 58C04100   mov     eax, dword ptr [g_pD3D]
00401078  |.  50            push    eax
00401079  |.  FF52 20       call    dword ptr [edx+20]               ;  d3d8.6DD3D510

而C代码如: g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ..很明显,C++将COM指针放进了堆栈的最后一个参数。如同C++的类的this指针一样。同样有趣的是,如果大家回忆一下C++对虚函数的编译方式就会发现 call    dword ptr [edx+20] 中的Edx = [[g_pD3D]]。这下可好了,我们要接管这个指针,我们可以先通过一个程序得到LPDIRECT3D8指针后,然后通过QueryInferace得到其他函数的指针。有了g_pD3D了,你就可以发挥自己的想象了。

      然后就要开始画图了,看看C代码的骨架:

     VOID Render()
    {
    if( NULL == g_pd3dDevice )
        return;

    // Clear the backbuffer to a blue color
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
    // Begin the scene
    g_pd3dDevice->BeginScene();
    // Rendering of scene objects can happen here
    // End the scene
    g_pd3dDevice->EndScene();
    // Present the backbuffer contents to the display
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
   }

显然,画游戏界面的就是在 BeginScene EndScene之间填写的。。然后通过Present函数显示出来。关于这3个函数的说明google出来结果如下:

BeginScene通过锁定后台缓冲区使设备准备好,以进行后续的操作。EndScene方法告知设备已经完成绘制,并取消后台缓冲区的锁定。必须始终在调用BeginScene之后调用EndScene,否则后台缓冲区将保持锁定状态。BeginScene和EndScene方法与Present方法紧密协作,一起管理后台缓冲区;如果其中一个方法失败,其他两个方法也会失败。

   又在查了下资料,其实Present只是把DX渲染好的图像显示出来。真正渲染的动作一般都放在BeginScene和EndScene之间。代码骨架如下:

 

   SetTransform ; ---坐标变换,包括旋转平移等等。

  for( DWORD i=0; i        {
            if( m_bUseMaterials )
            {
                if( m_pMaterials[i].Diffuse.a < 1.0f )
                    continue;
                pd3dDevice->SetMaterial( &m_pMaterials[i] );
               pd3dDevice->SetTexture( 0, m_pTextures[i] );
            }
            m_pLocalMesh->DrawSubset( i );
        }

   m_pd3dDevice->SetStreamSource( 0, m_pEarthVB, sizeof(BUMPVERTEX) );  ////这里把要渲染的顶点坐标送入T&L管线
    m_pd3dDevice->SetVertexShader( D3DFVF_BUMPVERTEX );

   m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, m_dwNumSphereVertices-2 );  /////渲染吧……

 

需要多说一嘴的是:

g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) 创建设备的时候,通过d3dpp参数可以指定一些重要参数。

image

这里指定了长,宽,多刷新缓冲的个数,是否窗口化这些参数。

 

  • DX_Draw

       dxDraw基本就是DX的那一套。通过DirectDrawCreateEx( NULL, (VOID**)&m_pDD,IID_IDirectDraw7, NULL ) ) )创建好dxdraw对象,记住是个COM指针。然后m_pDD->SetCooperativeLevel( hWnd, DDSCL_NORMAL );设置协作模式,这里可以窗口化或者全屏化。然后m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL )创建画图的Surface,通过这个参数m_pddsFrontBuffer你可以指定详细创建的参数。

同样,在WM_PAINT消息中画游戏显示,其中很多函数和GDI函数名字相同。没又需要多说的。D3D替代DDraw是趋势。

 

  • DX_Input

         同样 DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION,  _IDirectInput8, (VOID**)&g_pDI, NULL ) ) )函数就可以创建一个IDirectInput8的COM指针。  DXIuput可以是键盘Keyboard或者鼠标Mouse.  g_pDI->CreateDevice( GUID_SysKeyboard, &g_pKeyboard, NULL ) 查询到键盘的COM指针 , g_pDI->CreateDevice( GUID_SysMouse, &g_pMouse, NULL ) ) )查询到鼠标的COM指针 。然后通过GetDeviceState函数就可以得到键盘和鼠标的输入信息了。

比如下面是查询是哪个键盘被按下了的代码:

  • 立即模式

BYTE    diks[256];

ZeroMemory( &diks, sizeof(diks) );
hr = g_pKeyboard->GetDeviceState( sizeof(diks), &diks );

hr = g_pKeyboard->Acquire();
while( hr == DIERR_INPUTLOST ) 
         hr = g_pKeyboard->Acquire();

for( i = 0; i < 256; i++ ) {
        if( diks[i] & 0x80 )
        {
            wsprintf( strElement, TEXT("0x%02x "), i );
            _tcscat( strNewText, strElement );
        }
    }

  • 缓冲模式

        hr = g_pKeyboard->Acquire();
        while( hr == DIERR_INPUTLOST )
            hr = g_pKeyboard->Acquire();

    for( i = 0; i < dwElements; i++ )
    {
        // this will display then scan code of the key
        // plus a 'D' - meaning the key was pressed
        //   or a 'U' - meaning the key was released
        wsprintf( strLetter, TEXT("0x%02x%s "), didod[ i ].dwOfs,
                                         (didod[ i ].dwData & 0x80) ? TEXT("D") : TEXT("U"));
        _tcscat( strNewText, strLetter );
    }

 

同样鼠标的如下:

  • 立即模式

DIMOUSESTATE2 dims2;

hr = g_pMouse->GetDeviceState( sizeof(DIMOUSESTATE2), &dims2 );

hr = g_pMouse->Acquire();
        while( hr == DIERR_INPUTLOST )
            hr = g_pMouse->Acquire();

_stprintf( strNewText, TEXT("(X=% 3.3d, Y=% 3.3d, Z=% 3.3d) B0=%c B1=%c B2=%c B3=%c B4=%c B5=%c B6=%c B7=%c"),
                         dims2.lX, dims2.lY, dims2.lZ,
                        (dims2.rgbButtons[0] & 0x80) ? '1' : '0',
                        (dims2.rgbButtons[1] & 0x80) ? '1' : '0',
                        (dims2.rgbButtons[2] & 0x80) ? '1' : '0',
                        (dims2.rgbButtons[3] & 0x80) ? '1' : '0',
                        (dims2.rgbButtons[4] & 0x80) ? '1' : '0',
                        (dims2.rgbButtons[5] & 0x80) ? '1' : '0',
                        (dims2.rgbButtons[6] & 0x80) ? '1' : '0',
                        (dims2.rgbButtons[7] & 0x80) ? '1' : '0');

 

  • 缓冲模式

DIDEVICEOBJECTDATA didod[ SAMPLE_BUFFER_SIZE ];

DWORD              dwElements;

hr = g_pMouse->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
                                     didod, &dwElements, 0 );

hr = g_pMouse->Acquire();
        while( hr == DIERR_INPUTLOST )
            hr = g_pMouse->Acquire();

for( i = 0; i < dwElements; i++ )
    {
        // this will display then scan code of the key
        // plus a 'D' - meaning the key was pressed
        //   or a 'U' - meaning the key was released
        switch( didod[ i ].dwOfs )
        {
            case DIMOFS_BUTTON0:
                _tcscat( strNewText, TEXT("B0") );
                break;

            case DIMOFS_BUTTON1:
                _tcscat( strNewText, TEXT("B1") );
                break;

            case DIMOFS_BUTTON2:
                _tcscat( strNewText, TEXT("B2") );
                break;

            case DIMOFS_BUTTON3:
                _tcscat( strNewText, TEXT("B3") );
                break;

            case DIMOFS_X:
                _tcscat( strNewText, TEXT("X") );
                break;

            case DIMOFS_Y:
                _tcscat( strNewText, TEXT("Y") );
                break;

            case DIMOFS_Z:
                _tcscat( strNewText, TEXT("Z") );
                break;

            default:
                _tcscat( strNewText, TEXT("") );
        }

        switch( didod[ i ].dwOfs )
        {
            case DIMOFS_BUTTON0:
            case DIMOFS_BUTTON1:
            case DIMOFS_BUTTON2:
            case DIMOFS_BUTTON3:
                if( didod[ i ].dwData & 0x80 )
                    _tcscat( strNewText, TEXT("U ") );
                else
                    _tcscat( strNewText, TEXT("D ") );
                break;

            case DIMOFS_X:
            case DIMOFS_Y:
            case DIMOFS_Z:
            {
                TCHAR strCoordValue[20];
                wsprintf( strCoordValue, TEXT("%d "), didod[ i ].dwData );
                _tcscat( strNewText, strCoordValue );
                break;
            }
        }
    }

========================================================

呵呵,通过大体研究,基本清楚。如有错误,初学者难免。

原创粉丝点击