Chinaunix首页 | 论坛 | 博客
  • 博客访问: 8699187
  • 博文数量: 1413
  • 博客积分: 11128
  • 博客等级: 上将
  • 技术积分: 14685
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-13 10:03
个人简介

follow my heart...

文章分类

全部博文(1413)

文章存档

2013年(1)

2012年(5)

2011年(45)

2010年(176)

2009年(148)

2008年(190)

2007年(293)

2006年(555)

分类: C/C++

2006-11-24 23:31:35

摘 要:把DirectXSDK封装在MFC的类中,建立一个DirectX应用程序框架。

关键词:MFC类库,DirectXSDK

一、 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”改为#i nclude“DirectXWnd.H”然后把CDirectXApp::InitInstance()函数修改如下,其中黑体字为要增加的内容:

BOOL CDirectXApp::lnitlnstnnce()

{

#ifdef _AFXDLL Enable3dControls();

color="#008000">//Call this when Using MFC in a shared DLL

#else Enable3dControlsStatic();

color="#008000">//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文件头加入下列

字符串:#i nclude"DirectXWnd.h"。

2.打开DirectX.CPP文件,在文件头加入#i nclude"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

#i nclude

#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

#i nclude "stdafx.h"

#i nclude "DirectX.h"

#i nclude "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、DirectX.zip,工程框架源文件;2、

href="">CTestWnd.zip,测试程序源文件。

使用这两个源程序时不要直接编译,因为没有包含编译需要的所有文件,而应该根据本文提示做,需要输入代码的时候,将该文件替换成下载包中的相应文件就可以。另外,请在运行时不要用ALT+TAB切换出来,否则会被锁住,非Reset不可。要想不被锁住,请深入研究DirectDraw技术修改此程序。

color="#0000FF">----无心柳

本文摘自《计算机编程技巧与维护》杂志1999年第3期

整理:无心柳(全部代码已经输入测试通过)1999/11/02

阅读(3606) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~