程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 用MFC構造DIRECTX應用框架

用MFC構造DIRECTX應用框架

編輯:關於VC++

一、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應用程序基本框架

我們按下列步驟建立一個勘rectXSDK程序的基本框架:

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;
}

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved