用MFC构造DirectX应用框架

    技术2022-05-11  120

    用MFC构造DirectX应用框架

    Microsoft DirectX SDK是开发基于 Windows 平台游戏的一个软件开发工具,其功能主要包括在五个组件中 :DirectDraw DirectSound DirectPlay Direct3DDirectInput,每个组件都具不中的功能:

    DirectDraw使用直接写存技术加快游戏的动画速度;

    DirectSound控制游戏声音的合成和播放;

    DirectPlay使游戏具有网络多人游戏功能;

    Direct3D让程序员更方便地开发三维游戏;

    DirectInput使游戏支持更多的办入设备(现在只支持游戏杆,鼠标和键盘)。

    可以说DirectX SDK提供了编写一个游戏 所必须的功能及基层函数,所以大多Windows游戏都使用了DirectX SDK.

    MFC(Microsoft Foundation Class)类库是Microsoft Visual C++中提供的一个功能强大的 Windows 应用程序开发类, 使用这些类我们可以避免和繁琐的Windows API打交道,而且在 Visual C++中我们还可以利用ClassWizard MFC 类进行Windows 消息映射,所以如果能用MFC 类库来开发DirectX SDK的应用程序,至少有以下几个好处:

    可以用VC++ClassWizard方便地对Windows消息进行映射;

    增加了程序的可读性,并且可以用VC++ ClassView方便的管理所用的类;

    增加程序代码的可重用性, 可以在原有的基础上开发出功能更强大的应用程序;

    更进一步,如果我们能开发出一个能生成DirectX SDK应用程序基本框架的VC++的工程向导,则为以后开发DirectX SDK应用于程序提供及大的方便。下面,我们将用Visual C++先编写一个DirectX SDK应用程序的基本框架。

    编写 DirectX SDK 应用程序基本框架

    我们按下列步骤建立一个DirectX SDK 程序的基本框架:

    1 Visual C ++MFC App Wizard (EXE) 生成一个基本对话框的工程文件,取名为DirectX,在向导第二步时取消About Box 的复选框,然后按Finish按钮。

    2 删除在DirectX 工程目录中生成的DirectXDlg.H两个文件,并在Visual C++File View中删除以上两个文件,按CTRL+W启动ClassWizard删除CdirectXDlg类,然后在ResourseView中删除IDD_DIRECTX_DIALOG.

    3 建立两个文件DirectXWnd.H(这两个文件在本文的附录中,请注意不要删除有“//{”和“//}”之间的内容,否则将不能使用ClassWizard对窗口信息进行映射),并把它们加入到工程中。这时工程中将加入一个基于CWndCdirectXWnd类,这是我们的DirectX应用程序的基类。CdirectXWnd类创建一个窗口并生成一个与该窗口相关联的DirectDraw对象lpDD,同时还生成一个显示平面(lpFrontBuffer)和一个显示缓冲平面(lpBackBuffer,该类使用了几个虚函数,必要时其派生类可以覆盖这些函数。

    4 打开DirectX.CPP, # include”DirectXDLG.h”改为 #include “DirectXWnd.H”然后把CdirectXApp::InitInstance()函数修改如下,其中黑体字为要增加的内容:

    BOOL CdirectXApp::initlnstance()

    {

    #ifdef_AFXDLL

    Enable3dControls();//Call this when using MFC in a shared DLL

    #else

    Enable3dConteolsStatic();//Call this when linking to MFC

    Statically

    #endif

    CdirectXWnd *pWnd =new CdirectXWnd();

    PWnd->Create(“DirectXWnd Test”);

    m-pMainWnd =pWnd;

    pWnd->UpdateWindow();

    pWnd->SetFocus();

    if (pWnd->initializeGame(640,480,8)= =FALSE){

    pWnd->DestroyWindow();

    return FALSE;

    }

    MSG msg;

    White(1)

    {

    if(PeekMessage(&msg,NULL,0,0,PM-NOREMOVE)) {

    if( !GetMessage(&msg,NULL,0,0))

    return msg.wParam;

    TranslateMessage(&msg);

    DispatchMessage(&msg);

    }

    else{

    if (pWnd->blsActive) {

    pWnd-> UpdateFrame();

    }

    }

    }

    return TURE;

    }

    编译该程序并运行,可以看到出现一个黑色的屏幕窗口,按ESCF12则可退出程序。至此我们的基本框架已经建立好了,虽然这个框架还比较简单,但我们可以在此基础上开发出更强大的应用框架。为了方便使用该框架,我们可以为该框架写一个Custom App Wizard,当然也可以不写,只要把该工程目录下的文件拷贝到另一个工程目录中即可。

    测试框架

    现在,我们按下列步骤写一个程序来测试这个框架:

    1 把刚才创建的工程框架拷贝到一个新目录下,并打开。用Class View 创建一个基于CWnd的类CtestWnd,然后把CtestWnd.hCtestWnd.CPP文件中的所有“CWnd”字符串替换为“CdirectXWnd”,并在CtestWnd.h文件头加入下列字符串:#include “DirectXWnd.h”.

    2 打开DirectX.CPP文件,在文件头加入# include “TestWnd.h”,并把该文件中的所有”CdirectXWnd”字符串替换成”CtestWnd”并保存。

    3 CtestWnd类增加一个虚函数UpdateFrame(),这个函数覆盖了其基类CdirectXWndUpdateFrame():

    void CtestWnd :: UpdateFrame()

    {

    staic int x= 0, dx =5;

    staic int y =0, dy =5;

    HDC hdc;

    DDBL TFX ddbltfx;

    HRESULT ddrval;

    UpdateWindow();

    Ddbltfx.swSize = sizedof(ddbltfx);

    Ddbltfx.dwFillColor = 0;

    Ddrval = lpBackBuffer ->Blt(

    NULL ,//dest rect

    NULL,//src surface

    NULL,// src rect

    DDBLT_COLORFILL |DDBLT_WAIT,

    &ddbltfx);

    if (ddrval ! = DD_OK)

    {

    msg(“ Fill failed ddrval =0x1x”,ddrval);

    return;

    }

    if (lpBackBuffer ->GetDC(&hdc) = =DD- OK)

    {

    if(x<0) dx=5;

    if(x>590) dx= -5;

    if (y<0) dy =5;

    if ( y>430) dy = -5;

    x += dx ; y + =dy;

    Ellipse( hdc ,x,y,x+50,y+50);

    LpBackBuffer ->ReleaseDC(hdc);

    }

    while(1)

    {

    HRESULT ddrval;

    ddrva =lp FrontBuffer->Flip(NULL,0);

    if( ddrval = =DD_ OK)

    {break;}

    if (ddravl= =DDERR_SURFACELOST)

    {

    if(!CdirectXWnd::RestoreSurfaces())

    {

    break;

    }

    }

    if (ddravl !=DDERR_WASSTILLDRAWING)

    {

    break;

    }

    }

    }4:编译并运行程序,屏幕上会出现一个白色球在移动

    附录:

    文件DirectXWnd.h

    #if !defined(DIRECTXWND-H)

    #define DIRECTXWND_H

    //DirectXWnd.h:header file

    #include<ddraw.h>

    #pragma comment (lib,ddrawLib)//链接时加入ddraw.lib

    class CdirectXWnd: public CWnd

    {

    //Construction

    public:

    CDirectXWnd();

    //Attributes

    public:

    BOOL blsActive; //应用程序是否激活

    protected:

    LPDERECTDRAW lpDD; //DirectDraw对象指针

    LPDERECTDRAWSURFACE lpFrontBuffer;//DirectDraw主缓冲区

    LPDERECTDRAWSURFACE lpBacdBuffer;//DirectDraw后备缓冲区

    int nBufferCount; //后备缓冲区个数

    //Operations

    protected:

    void Msg(LPSTR fmt,...);

    public:

    BOOL Create(LPCSTR lpszAppName); //创建窗体

    //Overrides

    virtual BOOL InitializeGame(UINT Gmodex,UINT GmodeY,UINT GBPP);

    virtual BOOL CleanSurface();

    virtual void UpdateFrame();

    virtual BOOL RestoreSurfaces(void);

    //{{AFX-VIRTUAL(CdirectXWnd)

    //}}AFX_VIRTUAL

    //Implementation

    public:

    virtual~CdirectXWnd();

    //Generated message map functions

    protected:

    //{{AFX-MSG(CderectXWnd)

    afx-msg void OnActivateApp(BOOL bActive, HTASK hTask);

    //}}AFX-MSG

    DECLARE-MESSAGE-MAP()

    };

    //{{AFX-INSERT-LOCATION}}

    #endif//!defined(DERECTXWND-H)

    文件DirectXWnd.CPP

    //DirectXWnd.cpp:implementation file

    #include”stdafx.h”

    #include”DirectX.h”

    #include”DirectXWnd.h”

    #ifdef-DEUG

    #define new DEBUG-NEW

    #undef THIS –FILE

    static char THIS –FILE[]=--FILE--;

    #endif

    CDirectXWnd::CdirectWXnd()

    {

    lpDD=NULL;

    lpFrontBuffer=NULL;

    lpBackBuffer=NULL;

    nBufferCount=0;

    blsActive=TRUE;

    }

    CDirectXWnd::~CdirectXWnd()

    {

    if(lpDD){

    CleanSurface();

    lpDD->Release();

    lpDD=NULL;

    }

    }

    BOOL CdirectXWnd::Create(LPCSTR IpszAppName)

    {

    CString className=AfxRegisterWndClass(CS-DBLCLKS,::LoadCursor(NULL,IDC-ARRWINDOW, className,IpszAppName,

    WS-VISIBLE | WS-SYSMENU | WS-POPUP, 0, 0, GetSystemMetrics(SM-CXSCREEN), GetSystemMetrics(SM-CYSCREEN),NULL,NULL));

    }

    BOOL CdirectXWnd::InitializeGame(UINT GmodeX,UINT GModeY, UINT GBPP)

    {

    HRESULT ddrval;

    ddrval=DirectDrawCreate(NULL,&lpDD,NULL);

    if(ddrval!=DD-OK){

    Msg(“DirectDrawCreate failed err=%d”, ddrval);

    return FALSE;

    }

    ddral=lpDD->SetCooperativeLevel(m-hWnd,DDSCL-EXCLUSIVE | DDSCL-FULLSCREEN);

    if(ddrval!=DD-OK){

    Msg(“SetCooperativeLevel failed err=%d”,ddrval);

    return FALSE;

    }

    ddrval=lpDD_>SetDisplayMode(GmodeX,GmodeY,GBPP);

    if(ddrval!-DD-OK)

    {

    Msg(“SetDisplayMode failed err=%d”,ddrval0;

    return FALSE;

    }

    //check capabilites

    DDCAPS ddcaps;

    ddcaps.dwSize=sizeof(ddcaps);

    ddrval=lpDD->GetCaps(&ddcaps,NULL);

    if(ddrval!=DD-OK){

    Msg(“SetDisplayMode failed err=%d”,ddrval);

    return FALSE;

    }

    if(ddcaps.dwCaps&DDCAPS_NOHARDWARE){

    Msg(“No hardware support at all”);

    }

    //default to double buffered on 1mb, triple buffered

    if(nBufferCount = =0){

    if(ddcaps.dwVidMemTotal<=1024L*1024L*(GBPP/8)| |

    GModeX>640){

    NBufferCount =2;

    }

    else{

    nBufferCount =3

    }

    }

    DDSURFACEDESC ddsd;

    : :ZeroMemory(&ddsd, sizeof(ddsd));

    ddsd.dwSize=sizeof(ddsd);

    ddsd.dwFlags=DDSD_CAPS| DDSD_BACKBUFFERCOUNT;

    ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE|

    DDSCAPS_FLIP |DDSCAPS_COMPLEX;

    ddsd.dwBackBufferCount=nBufferCount_1;

    ddrval=lpDD_>CreateSurface(&ddsd,&lpFrontBuffer,NULL);

    if(ddrval !=DD_OK){

    Msg(“CreateSurface failed err=%d”,ddrval);

    return FALSE;

    }

    DDSCAPS ddscaps;

    ddscaps.dwCaps=DDSCAPS_BACKBUFFER;

    ddrval=lpFrontBuffer_>GetAttachedSurface(&ddscaps,&lpBackBuffer);

    if(ddrval !=DD_OK){

    Msg(“GetAttachedsurface failed err=%d”,ddrval);

    return FALSE;

    }

    return TRUE;

    }

    void CdirectXWnd: :Msg(LPSTR FMT, ...)

    {

    char buff[256];

    va_list va;

    lstrcpy(buff,”DirectxWnd:”);

    va_start(va,fmt);

    wvsprintf(&buff[lstrlen(buff)],fmt,va);

    va_end(va);

    lstrcat(buff,”/r/n”);

    AfxMessageBox(buff);

    }

    //

    //Virtual Function

    BOOL CdirectXWnd: :RestoreSurfaces()

    {

    HRESULT ddrval;

    ddrval = lpFrontBuffer_>Restore();

    if(ddrval !=DD_OK)

    return FALSE;

    return TRUE;

    }

    BOOL CDirectXWnd: :CleanSurface()

    }

    if(lpBackBuffer){

    lpBackBuffer_>Release();

    lpBackBuffer=NULL;

    }

    if(lpFrontBuffer){

    lpFrontBuffer_>Release();

    lpFrontBuffer=NULL;

    }

    return TRUE;

    }

    void CDirectSWnd: :UpdateFrame()

    {

    }

    BEGIN_MESSAGE_MAP(CdirectXWnd,CWnd)

    //{{AFX_MSG_MAP(CdirectXWnd)

    ON_WM_KEYDOWN()

    ON_WM_ACTIVATEAPP()

    //}}AFX_MSG_MAP

    END_MESSAGE_MAP()

    /

    //CDirectXWnd message gandlers

    void CDirectXWnd: :OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)

    {

    switch(nChar)

    {

    case VK_ESCAPE:

    case VK_F12:

    PostMessage(WM_CLOSE);

    break;

    }

    CWnd: :OnKeyDown(nChar, nRepCnt, nFlags);

    }

    void CdirectXWnd: :OnActivateApp(BOOL bActive,HTASK hTask){

    CWnd: :OnActivateApp(bActive,hTask);

    BlsActive=bActive;

    }


    最新回复(0)