• 【转】用MFC构造DIRECTX应用框架


    一、 MFC类库与DirectXSDK

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

    .DirectDraw使用直接写存技术加快游戏的动画速度;
    .DirecSound控制游戏声音的合成和播放;
    .DirectPlay使游戏具有网络多人游戏功能;
    .Direct3D让程序员更方便地开发三维游戏:
    .DirectInput使游戏支待更多的输入设备(现在只支持游戏杆、鼠标和键盘)。

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

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

    1.可以用 VC++的 C1assWizard方便地对Windows消息进行映射;
    2.增加了程序的可读性,并且可以用VC++的ClassView方便的管理所用的类;
    3. 增加程序代码的可重用性,可以在原有的基础上开发出功能更强大的应用程序更进一步,如果我们能开发出一个能生成DirectXSDK应用程序基本框架的 VC++的工程向导,则为以后开发DirectX SDK应用程序提供及大的方便。下面,我们将用Visua1 C++5.0先编写一个DirectXSDK应用程序的基本框架。

    二、编写DirectXSDK应用程序基本框架

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

    1.用 Visual C++的 MFC AppWizard(EXE)生成一个基于对话框的工程文件,取名为DirectX,在向导第二步时取消About Box的复选框,然后按Finish按钮。
    2. 删除在DirectX工程目录中生成的DirectXDlg.CPP和DirectXDlg.H两个文件,并在Visual C++的FileView中删除以上两个文件,按CTRL十W启动ClassWizard删除CDirectXDlg类,然后在ResourceView 中删除 IDD_DIRECTX_
    DIALOG。
    3.建立两个文件 DirectXWnd.CPP和DirectXWnd.H(这两个文件在本文的附录中,请注意不要删除有“\\{”和“\\}”之间的内容,否则将不能使 用ClassWizard对窗口消息进行映射),并把它们加入到工程中。这时工程中将增加一个基于CWnd的CDirectXWnd类,这是我们的 DirrectX应用程序的基类。CDirectXWnd类创建一个窗口并生成一个与该窗口相关联的DirectDraw对象lpDD,同时还生成一个显 示平面(lpFrontBuffer)和一个显示缓冲平面(lpBackBuffer),该类使用了几个虚函数,必要时其派生类可以覆盖这些函数。
    4.打开DirectX.CPP,把# include“DirectXDlg.h”改为#include“DirectXWnd.H”然后把CDirectXApp::InitInstance()函数修改如下,其中黑体字为要增加的内容:

    BOOL CDirectXApp::lnitlnstnnce()
    {
        #ifdef _AFXDLL    Enable3dControls();//Call this when Using MFC in a shared DLL
        #else    Enable3dControlsStatic();//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;
        while(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 FALSE;
    }
    编 译该程序并运行,可以看到出现一个黑色的屏幕窗口,按ESC或F12则可退出程序。至此,我们的基本框架已经建立好了,虽然这个框架还比较简单,但我们可 以在此基础上开发出更强大的应用框架。为了方便使用该框架,我们可以为该框架写一个Custom AppWizard,当然也可以不写,只要把该工程目录下的文件拷贝到另一个工程目录中即可。

    三、测试框架

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

    1.把刚才创建的工程框架拷贝到一个新目录下,并打开。用C1assView创建一个 基于CWnd的类CTestWnd,然后把CTestWnd.h和CTestWnd.CPP文件中的所有"CWnd"字符串替换为 "CDirectXWnd",并在CTestWnd.h文件头加入下列
    字符串:#include"DirectXWnd.h"。
    2.打开DirectX.CPP文件,在文件头加入#include"TestWnd.h",并把该文件中的所有"CDirectXWnd"字符串替换成"CTestWnd"并保存。
    3.为 CTestWnd类增加一个虚函数UpdateFrame(),这个函数覆盖了其基类CDirectWnd的UpdateFrame():

    void CTestWnd::UpdateFrame()
    {
        static int x=0,dx=5;
        static int y=0,dy=5;
        HDC hdc;
        DDBLTFX ddbltfx;
        HRESULT ddrval;
        UpdateWindow();
        ddbltfx.dwSize=sizeof(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=0x%081x",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;
            ddrval=lpFrontBuffer->Flip(NULL,0);
            if(ddrval==DD_OK)
            {
                break;
            };
            if(ddrval==DDERR_SURFACELOST)
            {
                if(!CDirectXWnd::RestoreSurfaces())
                {
                    break;
                }
            }
            if(ddrval!=DDERR_WASSTILLDRAWING)
            {
                break;
            }
        }
    }

    无心柳按:光是这么追加在测试中没有成功,可能要在CTestWnd.H中追加两行:
    public:
        void    UpdateFrame();
    否则编译可能出错。

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

    附录:

    文件:DirectXWnd.H

    #if!defined(DIRECTXWND_H)
    #define DIRECTXWND_H
    //DirectXWnd.h:header file
    #include<ddraw.h>
    #pragma comment(lib,"ddraw.lib")//链接时加入ddraw.lib库

    class CDirectXWnd:public CWnd
    {
    //Construction
    public:
        CDirectXWnd();
        //Attributes
    public:
        BOOL blsActive;//应用程序是否被激活
    protected:
        LPDIRECTDRAW lpDD;//DirectDraw对象指针
        LPDIRECTDRAWSURFACE lpFrontBuffer;//DirectDraw主缓冲区
        LPDIRECTDRAWSURFACE lpBackBuffer;//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(CDirectXWnd)
        afx_msg void OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags);
        afx_msg void OnActivateApp(BOOL bActive,HTASK hTask);
        //}}AFX_MSG
        DECLARE_MESSAGE_MAP()
    };
    ////////////////////{{AFX_INSERT_LOCATION}}
    #endif//!define(DIRECTXWND_H)

    文件:DirectXWnd.CPP
    //DirectXWnd.cpp:implementation file
    #include "stdafx.h"
    #include "DirectX.h"
    #include "DirectXWnd.h"
    #ifdef _DUBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[]=__FILE__;
    #endif
    CDirectXWnd::CDirectXWnd()
    {
        lpDD=NULL;
        lpFrontBuffer=NULL;
        lpBackBuffer=NULL;
        nBufferCount=0;
        blsActive=TRUE;
    }
    CDirectXWnd::~CDirectXWnd()
    {
        if(lpDD)
        {
            CleanSurface();
            lpDD->Release();
            lpDD=NULL;
        }
    }
    BOOL CDirectXWnd::Create(LPCSTR lpszAppName)
    {
        CString className=AfxRegisterWndClass(CS_DBLCLKS,::LoadCursor(NULL,IDC_ARROW),
            NULL,AfxGetApp()->LoadIcon(IDR_MAINFRAME));
        return(CWnd::CreateEx(WS_EX_APPWINDOW,className,lpszAppName,
            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;
        }
        ddrval=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",ddrval);
            return FALSE;
        }
        //check capabilites
        DDCAPS ddcaps;
        ddcaps.dwSize=sizeof(ddcaps);
        ddrval=lpDD->GetCaps(&ddcaps,NULL);
        if(ddrval!=DD_OK)
        {
            Msg("GetCaps 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;
        }
        else Msg("显示内存允许建立的缓冲区数=%d(最多需要3)",nBufferCount);
        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 CDirectXWnd::UpdateFrame()
    {
    }
    BEGIN_MESSAGE_MAP(CDirectXWnd,CWnd)
    //{{AFX_MSG_MAP(CDirectXWnd,Cwnd)
    ON_WM_KEYDOWN()
    ON_WM_ACTIVATEAPP()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    ///////////////////CDirectXWnd message handlers
    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;
        return;
    }

    抱歉,实在没有找到原创作者,谢了先!

  • 相关阅读:
    [NOI2015]程序自动分析
    D-query(莫队)
    小B的询问
    组合的输出 (dfs+记忆化)
    组合的输出 (dfs+记忆化)
    5719: 集合的划分(dfs)
    Search for a range, 在一个可能有重复元素的有序序列里找到指定元素的起始和结束位置
    Find Min In Rotated Sorted Array2,包含重复数字的反转序列找最小值。
    Find Min In Rotated Sorted Array,寻找反转序列中最小的元素。
    Search In Rotated SortedArray2, 有重复数据的反转序列。例如13111.
  • 原文地址:https://www.cnblogs.com/dahai/p/1770139.html
Copyright © 2020-2023  润新知