MFC架构下的DirectX8

2016-02-19 17:11 0 1 收藏

下面这个MFC架构下的DirectX8教程由图老师小编精心推荐选出,过程简单易学超容易上手,喜欢就要赶紧get起来哦!

【 tulaoshi.com - 编程语言 】

  第一章 MFC框架 

  (DX8MFC) 

  这里的MFC框架指的是一个符合游戏开发应用的框架,当然你也可以写一个符合你要求的MFC框架。如果你对MFC比较熟悉的话可以直接从第二章开始阅读。本框架是以后几个例子的基础,如果你对MFC不是很了解的话,就要认真阅读本章,以求对这个MFC框架有一个深入的了解。 

  框架中包括两个类: 

  CDX8MFCApp类和CFrameWin类,CDX8MFCApp类是应用程序类,CFrameWin类是框架的主类,以后我们的大部分代码都是从这里扩展的。首先来看一看CDX8MFCApp类,它包括CDX8MFCApp()、ExitInstance()、InitInstance()、OnIdle(LONG lCount)等成员函数和一个Game对象。 

  InitInstance()成员函数在程序初始化时就被调用,在这里我建立了一个窗口: 

  

BOOL CDX8MFCApp::InitInstance() { // The one and only window has been initialized, so show and update it. m_pMainWnd = new CFrameWin(); m_pMainWnd-ShowWindow(m_nCmdShow); m_pMainWnd-UpdateWindow(); Game = (CFrameWin*) m_pMainWnd; Game-Init(); return TRUE; } 

  ExitInstance()成员函数在程序终止时被调用,在这里我们释放一些对象和指针: 

  

int CDX8MFCApp::ExitInstance() { // TODO: Add your specialized code here and/or call the base class Game-End(); delete Game; return CWinApp::ExitInstance(); } 

  OnIdle(LONG lCount)成员函数会在没有Windows消息要处理的时候被调用,也就是说OnIdle()成员函数会不断的被调用,这正好被我们用作游戏循环。 

  

BOOL CDX8MFCApp::OnIdle(LONG lCount) { // TODO: Add your specialized code here and/or call the base class if(Game-window_active==TRUE) { Game-Active(); Game-window_active=FALSE; } Game-Go(); return TRUE; } 

  Game对象是一个CFrameWin类指针,我们在InitInstance()成员函数中创建了一个CFrameWin对象并把CFrameWin对象的指针值赋给Game。 

  下面我们来看一看CFrameWin类,它包括Active()、End()、Go()、Init()、Update()等成员函数。 

  Init()成员函数,你可以在这里做一些自己的初始化。回顾CDX8MFCApp类的InitInstance()成员函数可知,在完成窗口初始化后InitInstance()成员函数里就调用了Game-Init(),也就是说Init()在窗口初始化后被调用。 

  

void CFrameWin::Init() { AfxMessageBox("Init"); }
 

  Go()成员函数会不断的被循环调用,它又调用了Update()和DestroyWindow()。Update()用于更新窗口,调用DestroyWindow()则会结束应用程序。如果你把DestroyWindow()语句删除掉,程序会不断的循环。 

  

void CFrameWin::Go() //Game循环 { AfxMessageBox("Go"); Update(); DestroyWindow(); } Active()成员函数会在应用程序被击活的时候被调用。 void CFrameWin::Active() //窗口被激活 { TRACE("Activen"); AfxMessageBox("Active"); } 

  这个程序并不做任何事,只是一个MFC框架。你可以从http://gamedev.363.net 下载例子的源程序,或通过E-mail: laical@21cn.com 向本文作者索取。 

  第二章 初始化DirectX8 

  (DX8MFC1) 

  本例将以第一章的MFC框架为基础对CFrameWin类进行扩展。主要加入了DrawScene()、InitDirect3D(HWND hwnd)和ShutdownDirect3D()三个函数。 

  

InitDirect3D(HWND hwnd)函数对Direct3D进行初始化: HRESULT CFrameWin::InitDirect3D(HWND hwnd) { pID3D = Direct3DCreate8(D3D_SDK_VERSION); HRESULT hr; do { // we need the display mode so we can get // the properties of our back buffer D3DDISPLAYMODE d3ddm; hr = pID3D-GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); if(FAILED(hr)) break; D3DPRESENT_PARAMETERS present; ZeroMemory(&present, sizeof(present)); present.SwapEffect = D3DSWAPEFFECT_COPY; present.Windowed = TRUE; present.BackBufferFormat = d3ddm.Format; hr = pID3D-CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice); if(FAILED(hr)) break; // we do our own coloring, so disable lighting hr = pID3DDevice-SetRenderState(D3DRS_LIGHTING, FALSE); } while(0); return hr; } 

  IDirect3D是我们首先要用到的接口,你可以这样写: 

  IDirect3D8 * pID3D = Direct3Dcreate8(D3D_SDK_VERSION); 

  在你使用pID3D以前,请检查pID3D是否为非空。 

  你下一步通常是创建D3D设备,但在创建D3D设备之前你要调用GetAdapterDisplayMode方法取得必须的信息: 

  D3DDISPLAYMODE d3ddm; 

  pID3D-GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); 

  接下来是取得当前显示模式参数。下面的参数是Surface格式。你可以用这些参数来创建一个D3DPRESENT_PARAMETERS结构: 

  D3DPRESENT_PARAMETERS present; 

  ZeroMemory(&present, sizeof(present)); 

  present.SwapEffect = D3DSWAPEFFECT_COPY; 

  present.Windowed = TRUE; 

  present.BackBufferFormat = d3ddm.Format; 

  D3DPRESENT_PARAMETERS描述了显示器Surface的信息,交换机制的类型,应用程序是窗口的还是全屏模式等信息。 

  在本例中,Surface是以拷贝方法代替页面翻转的,因为它是一个窗口模式的应用程序。把后台表面设置成与当前显示模式相匹配的格式,一个准备显示的Surface可以Draw在后台表面上。 

  现在你可以创建一个IDirect3DDevice8接口了: 

  

pID3D-CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present, &pID3DDevice); 

  这个函数有六个参数,幸运的是没有一个是很复杂的。D3DADAPTER_DEFAULT告诉Direct3D使用主显示器,只有当你使用多显示器时才是必须的。你可以使用一个数值来指定另外一个显示器。调用IDirect3D的GetAdapterCount将返回系统的适配器数目。 

  第二个参数,D3DDEVTYPE_HAL,告诉Direct3D使用硬件加速。其它选项包括D3DDEVTYPE_REF 和 D3DDEVTYPE_SW,通常你都会希望使用硬件加速的,但有时侯你可能会使用软件加速进行测试。 

  指定窗口取得焦点。如果是全屏应用程序,你需要一个最顶层窗口。 

  D3DCREATE_SOFTWARE_VERTEXPROCESSING指定顶点处理类型。你也可以使用硬件加速或是联合类型,我不使用硬件加速为的是广泛的兼容性。如果你想支持T&L,则你必须使用硬件加速。 

  最后两个参数很简单,一个是你以前建立的,而pID3Ddevice是你现在要创建的IDirect3DDevice8接口。如果方法返回D3DERR_NOTAVAILABLE,则你写的参数是正确的,但你的设备不支持你指定的参数。 

  最完美的是这个方法自动为你创建后台缓冲(back buffers)和深度缓冲(depth buffers)。剪裁(Clipping)作为后台表面(backface culling)被自动激活。灯光也被自动激活了,直到你定义顶点颜色之前,你可以禁止使用灯光: 

  pID3DDevice-SetRenderState(D3DRS_LIGHTING, FALSE); 

  DrawScene()函数: 

  

HRESULT CFrameWin::DrawScene() { HRESULT hr; do { // clear back buffer hr = pID3DDevice-Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_RGBA(0,63,0,0), 0, 0); if(FAILED(hr)) break; // start drawing hr = pID3DDevice-BeginScene(); if(FAILED(hr)) break; // Put all drawing code here hr = pID3DDevice-EndScene(); if(FAILED(hr)) break; // flip back buffer to front hr = pID3DDevice-Present(NULL, NULL, NULL, NULL); } while(0); return hr; } 

  Clear会填充你指定的缓冲区。你可以填充Z缓冲区、后台缓冲区或摸板缓冲区(stencil buffer)。在这个例子中你将用绿色填充后台缓冲区。所以,我们设定D3DCLEAR_TARGET标志和绿色。 

  在本例中BeginScene和EndScene并没有做什么,但在以后的例子中我们会用到它的。这两个函数是画图元时的例行公事代码, 

  这个函数不断的翻转后台表面。我们可以不断的在后台表面画一些东西,然后把后台表面翻转到前台表面。 

  ShutdownDirect3D()函数 

  

void CFrameWin::ShutdownDirect3D() { HELPER_RELEASE(pTexture); HELPER_RELEASE(pIndexBuffer); HELPER_RELEASE(pStreamData); HELPER_RELEASE(pID3DDevice); HELPER_RELEASE(pID3D); } 

  ShutdownDirect3D释放所有的接口。将来你可能要加入额外的代码来关闭Direct3D接口,但现在已经够了。如果你运行程序,你将得到一个绿色背景的窗口。你可以按ESC键来退出应用程序。 

  第三章 画三角形 

  (DX8MFC2) 

  定义你的顶点格式,Direct3D引入了一种可变形顶点格式(flexible vertex format)(FVF)的概念。在FVF中,你定义一个结构其中包括所需要的顶点组成部分。这个结构会随着你的程序而改变,但在这里你将初步把它定义成这个样子: 

  

struct MYVERTEX { FLOAT x, y, z; // The transformed position FLOAT rhw; // 1.0 (reciprocal of homogeneous w) DWORD color; // The vertex color }; 

  示例的开始定义了一个顶点结构,顶点的名称,和每一个三角形的顶点。在你的InitDirect3D函数中,你必须创建一个顶点缓冲区: 

  

int num_elems = sizeof(vertices) / sizeof(vertices[0]); pID3DDevice-CreateVertexBuffer(sizeof(MYVERTEX) * num_elems, D3DUSAGE_WRITEONLY, D3DFVF_XYZRHW|D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &pStreamData); 

  函数的第一个参数是顶点结构的字节大小。在应用程序还不能读取顶点之前,传一个D3DUSAGE_WRITEONLY标记给它。这里可以有不同的标记来指定如何处理你的顶点,但现在你可以确信Direct3D已经能正确的工作了。 

  下一步,指定我们用的是什么FVF格式。当你还没有使用坐标系预转换之前,指定为D3DFVF_XYZRHW标记。以后你使用自己的矩阵坐标系转换时,把它改成D3DFVF_XYZ。D3DFVF_DIFFUSE告诉Direct3D,我们将为每一个顶点指定颜色。D3DPOOL_DEFAULT指定内存的管理模式。 

  最后一个参数是顶点缓冲区的指针,在例子1中你已经定义了它,但并没有用上。 

  如果你不向顶点缓冲区填入有用数据的话,顶点缓冲区是没有用的: 

  

MYVERTEX *v; pStreamData-Lock(0, 0, (BYTE**)&v, 0); for(int ii = 0; ii  num_elems; ii++) { v[ii].x = vertices[ii].x; v[ii].y = vertices[ii].y; v[ii].z = vertices[ii].z; v[ii].rhw = vertices[ii].rhw; v[ii].color = vertices[ii].color; } pStreamData-Unlock(); 

  这是不难理解的,Lock返回一个你想写入顶点数据的指针。下一步你从你的顶点阵列中拷贝数据。然后,反还这个指针。 

  这一对的调用可以告诉Direct3D你的FVF格式,并设定顶点阵列为当前的活动顶点阵列。(你可以有多个顶点阵列)。 

  pID3DDevice-SetVertexShader(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); 

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  pID3DDevice-SetStreamSource(0, pStreamData, sizeof(MYVERTEX)); 

  SetVertexShader告诉Direct3D使用与CreateVertexBuffer同样的格式。 

  SetStreamSource告诉Direct3D使用pStreamData作为当前顶点阵列,并取得所有元素的大小。 

  你现在可以加入画三角形的代码了。在DrawScene()的BeginScene和EndScene之间加入如下代码: 

  int num_elems = sizeof(vertices) / sizeof(vertices[0]); 

  pID3DDevice-DrawPrimitive(D3DPT_TRIANGLELIST, 

  0, 

  num_elems / 3); 

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  D3DPT_TRIANGLELIST标记将命令Direct3D画不连续的三角形。你指定从索引的第0个顶点开始,指定所要画的三角形数目。 

  如果正确的话,你会看到一个三角形画在先前的绿色背景窗口上。 

  第四章 画索引三角形 

  (DX8MFC3) 

  上一章的画三角形方式运行效率是较低的,而实际上我们都会使用DrawIndexedPrimitive()而不是DrawPrimitive()。想一想,如果要画两个相连的三角形,共有四个顶点。用DrawIndexedPrimitive()画要画四个顶点,而用DrawPrimitive()画则要画六个顶点。 

  如果你可以顶点建立索引,你就可以用DrawIndexedPrimitive()画三角形了。我们可以为一个三角形建立这样的索引: 

  WORD indices[] = { 0, 1, 2 }; 

  它表示三角形中,第一个顶点对应于顶点阵列的第0个顶点;三角形中,第二个顶点对应于顶点阵列的第1个顶点;三角形中,第三个顶点对应于顶点阵列的第2个顶点; 

来源:https://www.tulaoshi.com/n/20160219/1614495.html

延伸阅读
使用MFC的数组类 作者:韩耀旭 下载源代码 MFC的数组类支持的数组类似于C++中的常规数组,可以存放任何数据类型。C++的常规数组在使用前必须将其定义成能够容纳所有可能需要的元素,而MFC数组类创建的对象可以根据需要动态地增大或减小,数组的起始下标是0,而上限可以是固定的,也可以随着元素...
我们做管理软件的,主要核心就在数据存储管理上。所以数据库设计是我们的重中之重。为了让我们的管理软件能够稳定、可扩展、性能优秀、可跟踪排错、可升级部署、可插件运行,我们往往研发自己的管理软件开发平台。我们总是希望去学习别人的开发平台(如用友或金蝶或SAP),但我们却总是感叹管理软件业务处理细节繁多,而数据库管理软件却简...
使用 MFC 编写打印程序 作者:戎亚新 南京航空航天大学仿真与控制实验室 下载源代码 摘要 本文首先介绍了利用MFC提供的文档视图框架来实现一个打印程序,实现打印预览,在此基础上,同时通过对MFC源代码的深入探讨,提出了利用该方法在对话框上用MFC实现打印功能,结果表明,利用MFC实现打...
标签: 电脑入门
在Windows 8中我们将不能在开机时按F8键进入安全模式,这是由于Windows 8新的安全启动机制所限制的。安全模式在某些情况下是非常有用的,新系统不知为什么把这个功能直接干掉了,想使用很是不方便,不过现在网上有大神找到了方法,如果你想通过开机按F8键进入安全模式,可通过下面的步骤实现。 那到底如何在Windows 8中找回F8下的安全模式呢?...
标签: ASP
  下面的代码是调用的DirectX的组件实现的时钟。它有三根指针,会实时地随系统时间的改变而改变。 不过我没有做刻度,因为我觉得用程序画出来的刻度不漂亮,用PHOTOSHOP画一口钟作为背景要漂亮多了。 <html <head <title指针式时钟</title <meta http-equiv="Content-Type" content="text/html; charset=...

经验教程

514

收藏

75
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部