Direct3D示例程序框架----DXUT解析【转载】

 

DXUT

  DXUT(The DirectX Utility Library) 是建立在Direct3D9 和Direct3D10 API上的一个程序框架。它的目标是建立一个强大而容易使用的Direct3D 游戏开发的示例、原型和工具。它简化了典型的Windows和Direct3D API的使用。
  DXUT是一种设计给游戏程序设计者用来节省编程时间和调试寻常问题(如:创建窗口、创建设备、处理窗口消息和控制设备事件)的程序框架。
  特别和局限:
  DXUT 帮助我们做以下工作:
  1、创建窗口。
  2、选择Direct3D设备。
  3、创建Direct3D设备。
  4、控制(操作)设备事件。
  5、处理窗口事件。
  6、连接(协调)窗口模式和全屏模式。
  DXUT 使用Direct3d 9 和Direct3D 10工作。建立在DXUT上的程序可以很容易的使用那些API。 如果DXUT检测到系统使用Direct3D10,并且程序可以使用Direct3D9或Direct3D10,他就会默认设置为Direct3D10;如果程序是以Direct3D10编写的话,系统不支持Direct3D10就会出错。
  DXUT也包含一套简单的GUI控制(GUI controls),一个激活输入的编辑框(IME-enable edit box),另外还有像简单的相机类型(class of simple Camera Type)和一个高级计时器(high-resolution timer)类。DXUT被设计成一种模型组合,所以程序可以使用所有的DXUT全部特点或一部分。
  虽然简单易用,但DXUT仅把一个单一设备放在单一的窗口中。像同时使用多种设备或显示多个Direct3D窗口这样的高级程序DXUT就不支持了。大部分程序可能会使用DXUT。
  使用DXUT的简单WinMain:
  INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, INT )
  {
  // Direct3D 9 回调信号
  DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable );
  DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice );
  DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice );
  DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender );
  DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice );
  DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice );
  // 设置 Direct3D 10回调信号
  DXUTSetCallbackD3D10DeviceAcceptable( IsD3D10DeviceAcceptable );
  DXUTSetCallbackD3D10DeviceCreated( OnD3D10CreateDevice );
  DXUTSetCallbackD3D10SwapChainResized( OnD3D10ResizedSwapChain );
  DXUTSetCallbackD3D10FrameRender( OnD3D10FrameRender );
  DXUTSetCallbackD3D10SwapChainReleasing( OnD3D10ReleasingSwapChain );
  DXUTSetCallbackD3D10DeviceDestroyed( OnD3D10DestroyDevice );
  // 设置通用的回调函数
  DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
  DXUTSetCallbackMsgProc( MsgProc );
  DXUTSetCallbackFrameMove( OnFrameMove );
  // 程序初始化
  // 初始化DXUT并创建程序中设计的窗口和Direct3D设备
  DXUTInit( true, true );
  DXUTCreateWindow( L"TestApp" );
  DXUTCreateDevice( true, 640, 480 );
  // 开始DXUT主要渲染循环
  DXUTMainLoop();
  // 程序清理
  return DXUTGetExitCode();
  }
  如果说Win32 API SDK中gdi部分是主旋律,那么MFC就是一个流行歌曲作家发挥之后完成的作品,而DXUT的图形框架则继承了Platform SDK中的风格,代码行间给人一种高贵的感觉。-,-扯远了,拉回来。因为gdi函数都是C API,不利于代码的重用,DXUT框架则把他们包装成了C++的类,以便于用户继承更改控件特性。D3D的知识学到这里基本上可以看懂DXUT框架了, 所以不必担心,但要是不理解Windows消息机制的话还是不行。 先了解一下DXUT中关于控件部分的设计架构比较好。这次看的代码大部分集中在DXUTgui.h和DXUTgui.cpp中。控件类的继承关系图是这样的:
  常用的控件大致都已经囊括在内,如果有特殊需要的话可以依葫芦画瓢从CDXUTControl继承。和这些控件有关系的还有几个重要的类,一个是 CDXUTDialog,这个类负责纪录一个对话框的所有属性以及它上面的所有控件信息。另一个是 CDXUTDialogResourceManager,这个类保存了所有注册过的对话框链表,以及这些对话框共享的资源。另外CDXUTElement 这个类保存了需要渲染的元素信息,经常会在渲染函数中用到,最后一个类是可动态增长的链表类CGrowableArray< TYPE >。这个模版类写的不错,不光能用在DXUT框架中,还可以用于很多其他场合。
  具体的代码太多了,这里挑重要的讲解。
   1.CDXUTDialog的Add系列函数。
  在初始化一个CDXUTDialog之后就是往这个对话框中添加控件了。在以前的例子中通常是在InitApp函数中调用对话框的Add系列函数来给对话框添加控件的。例如
  g_HUD.Init( &g_DialogResourceManager );
  g_HUD.SetCallback( OnGUIEvent ); int iY = 10;
  g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  前面两句分别是初始化和设定消息处理回调函数,最后一句是Add系列函数,这个用来在对话框特定位置添加一个特定控件。
   2.CDXUTDialog::MsgProc
  这个函数是处理对话框消息的。具体处理的消息包括该对话框的移动消息,优先处理焦点控件的消息,对话框大小和移动消息,获得焦点消息,键盘、鼠标消息,以及鼠标丢失消息。了解这些有助于我们充分利用这些功能,并添加自己想要的功能。
   3.控件的初始化和显示
  每个控件都有其特定的属性。如果程序为每种控件定义一些默认属性,可以省去我们重复定义的很多麻烦。了解这些我们可以在此基础上修改这些默认属性,使你的控件更加个性化。在DXUT中控件的默认属性是按照这样的步骤定义和应用的。
  ① 在初始化对话框的函数CDXUTDialog::Init中调用InitDefaultElements()为每种控件设定默认属性。
  ② 将这些默认属性添加到CDXUTDialog::m_DefaultElements中
  ③ 用户代码调用Add系列函数添加控件。这个Add函数调用CDXUTDialog::AddControl函数,并完成这个控件的一些设置。
  ④ CDXUTDialog::AddControl函数调用CDXUTDialog::InitControl初始化控件,并将该控件添加至对话框的CDXUTDialog::m_Control控件列表中。
  ⑤ CDXUTDialog::InitControl函数中遍历对话框的默认控件列表,并找到和要添加控件类型相同的默认控件,获得它的属性并将其设定到这个控件对象中。这个操作由CDXUTControl::SetElement函数来完成。
  ⑥ 在CDXUTControl的继承类(例如CDXUTButton)的Render函数中使用这些属性并且通过CDXUTDialog的DrawSprite函数画出图形,用CDXUTDialog的DrawText画出文字。
  要做一个漂亮的界面肯定少不了对控件的背景进行设置,例如用来显示文字的static控件,如果能用圆形表示那多好。但遗憾的是CDXUT框架中没有给 我们提供这些功能,需要我们自己去实现。它甚至没有给我们提供映射纹理的功能,而仅仅是提供了修改控件背景和前景字体颜色的功能。这些信息都放在空间的 m_Elements属性中,并由上述过程初始化。
  控件的显示在上面第六步有说明,就是调用DrawSprite和DrawText来实现。
   4.对话框的初始化和显示
  DXUT框架中的对话框和GDI的有相似的地方,又有不同的地方。最大的不同就在于DXUT框架中的对话框是通过Draw*函数画出来的,因此每一桢都 需要进行渲染,并且这些对话框是在主窗口内;而GDI的对话框是弹出式的,因此不属于原窗口。对话框的初始化在CDXUTDialog::Init系列函 数中。这个函数除了注册给CDXUTDialogResourceManager之外还进行了纹理的设置。在默认情况下框架在 OnCreateDevice时调用CDXUTDialogResourceManager的CreateTexture函数从内存创建纹理,而如果在 CDXUTDialog::Init函数中指定了纹理路径,或者指定使用资源中的纹理时,程序就从指定地点获得纹理。对话框采用一个列表来维护它的纹理, 在通常情况下只有这个列表中只有一个纹理,除非用户调用相关函数手动添加。这个纹理是在显示控件的时候作为参数传给DrawSprite的,因此并不会用 来作为对话框背景。
  对话框的显示使用CDXUTDialog::OnRender函数来实现。
  这个函数很关键,研究这个函数可以知道一个对话框是如何渲染的。和gdi应用程序不一样,DXUT框架是通过Draw*函数将控件画出来的,因此您可以 按照喜欢的方式自己设定按钮等控件的样子。可以想象CDXUTDialog::OnRender的主要任务就是调用每个控件的OnRender函数。在调 用这些OnRender函数之前可以先将这个对话框的背景画好。因此这个函数的伪代码看起来就是这样子的:
  ①进行一些判断;
  ②为对话框背景设定渲染状态和纹理阶段状态;
  ③禁用顶点shader和像素shader,并且画出对话框背景;
  ④再次设定纹理阶段状态,为画控件做准备;
  ⑤调用各控件的Render函数画出各控件,对于获得焦点的控件做特殊处理;
  这个函数使用了状态块来记录设定过的状态,以备后用。
  5.CD3DSettingDlg
  研究CD3DSettingDlg类可以学会如何使用上面的这些框架实现一个自己的对话框。我们可以在一个对话框上画另一个对话框,也可以选择在整个画 面中只画一个对话框。这些可以在主回调函数OnFrameRender中设定。例如在处理CD3DSettingDlg对话框的Active属性值被设定 为true的时候不处理其他对话框的渲染。
  if( g_SettingsDlg.IsActive() )
  {
  g_SettingsDlg.OnRender( fElapsedTime );
  return;
  }
  在主回调函数MsgProc处理消息的时候,如果CD3DSettingDlg已经处理过则不再传递给其他函数。
  if( g_SettingsDlg.IsActive() )
  {
  g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
  return 0;
  }
  CD3DSettingDlg::Init 初始化
  CD3DSettingDlg::CreateControls 添加控件
  CD3DSettingDlg::OnCreateDevice 设定消息处理回调函数
  CD3DSettingDlg::StaticOnEvent 消息处理回调函数,调用OnEvent
  CD3DSettingDlg::OnEvent 消息处理函数
  CD3DSettingDlg::OnRender 渲染
  ……
  在游戏中经常要进行游戏状态的切换,用户通过输入来出发某个游戏状态切换时,我们就可以重新绘制场景,而设计一个类似于CD3DSettingDlg来 实现是一个不错的注意。由于CreateControls函数和OnEvent函数在不同的场景中代码不同,因此可以在基类中将其设为virtual。可 以根据需要将OnRender, OnXXX系列函数设为虚函数,以便子类实现相应功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值