【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 2632|回复: 0

用MFC构造DIRECTX应用框架

[复制链接]
发表于 2006-12-11 23:44:15 | 显示全部楼层 |阅读模式
一、 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,:oadCursor(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;
  }

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 07:08

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表