登录社区:用户名: 密码: 忘记密码 网页功能:加入收藏 设为首页 网站搜索  

文档

下载

图书

论坛

安全

源码

硬件

游戏
首页 信息 空间 VB VC Delphi Java Flash 补丁 控件 安全 黑客 电子书 笔记本 手机 MP3 杀毒 QQ群 产品库 分类信息 编程网站
  立华软件园 - 安全技术中心 - 技术文档 - 入门基础 技术文章 | 相关下载 | 电子图书 | 攻防录像 | 安全网站 | 在线论坛 | QQ群组 | 搜索   
 安全技术技术文档
  · 安全配制
  · 工具介绍
  · 黑客教学
  · 防火墙
  · 漏洞分析
  · 破解专题
  · 黑客编程
  · 入侵检测
 安全技术工具下载
  · 扫描工具
  · 攻击程序
  · 后门木马
  · 拒绝服务
  · 口令破解
  · 代理程序
  · 防火墙
  · 加密解密
  · 入侵检测
  · 攻防演示
 安全技术论坛
  · 安全配制
  · 工具介绍
  · 防火墙
  · 黑客入侵
  · 漏洞检测
  · 破解方法
 其他安全技术资源
  · 攻防演示动画
  · 电子图书
  · QQ群组讨论区
  · 其他网站资源
最新招聘信息

MFC架构下的DirectX8
发表日期:2007-01-17作者:[转贴] 出处:  

第一章 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("Active\n"); 
    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); 

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

D3DPT_TRIANGLELIST标记将命令Direct3D画不连续的三角形。你指定从索引的第0个顶点开始,指定所要画的三角形数目。 
如果正确的话,你会看到一个三角形画在先前的绿色背景窗口上。 

第四章 画索引三角形 
(DX8MFC3) 
上一章的画三角形方式运行效率是较低的,而实际上我们都会使用DrawIndexedPrimitive()而不是DrawPrimitive()。想一想,如果要画两个相连的三角形,共有四个顶点。用DrawIndexedPrimitive()画要画四个顶点,而用DrawPrimitive()画则要画六个顶点。 
如果你可以顶点建立索引,你就可以用DrawIndexedPrimitive()画三角形了。我们可以为一个三角形建立这样的索引: 
WORD indices[] = { 0, 1, 2 }; 
它表示三角形中,第一个顶点对应于顶点阵列的第0个顶点;三角形中,第二个顶点对应于顶点阵列的第1个顶点;三角形中,第三个顶点对应于顶点阵列的第2个顶点; 
要画索引三角形,首先要建立索引缓冲: 
num_elems = sizeof(indices) / sizeof(indices[0]); 
pID3DDevice->CreateIndexBuffer(sizeof(WORD) * num_elems, D3DUSAGE_WRITEONLY, 
                        D3DFMT_INDEX16, D3DPOOL_DEFAULT, &pIndexBuffer); 
第二步是用顶点填充这个索引缓冲: 
WORD *pIndex; 
pIndexBuffer->Lock(0, 0, (BYTE **)&pIndex, 0); 
for(ii = 0; ii < num_elems; ii++) 

    pIndex[ii] = indices[ii]; 

pIndexBuffer->Unlock(); 

设定索引缓冲: 
pID3DDevice->SetIndices(pIndexBuffer, 0); 
把DrawScene()的相应的pID3DDevice->DrawPrimitive(...)换成: 
pID3DDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 
                                sizeof(indices) / sizeof(indices[0]), 0, 
                                sizeof(indices) / sizeof(indices[0]) / 3); 

运行程序的到的还是一个三角形。 

第五章 加入帖图 
(DX8MFC4) 
首先,在MYVERTEX结构中加入帖图坐标系tu和tv,并给顶点阵列赋以适当的值。 
下一步,设置你的帖图: 
D3DXCreateTextureFromFile(pID3DDevice, "dx5_logo.bmp", &pTexture); 
pID3DDevice->SetTexture(0, pTexture); 

其中的"dx5_logo.bmp"指的是帖图文件,你可以用其他的文件代替它,运行程序你会看到一个带帖图的三角形。 

第六章 帖图立方体 
(DX8MFC5) 
现在样我们来进入三维的世界吧!这里你要启用Z缓冲(z-buffer),设置立方体的材质,世界坐标系和投影坐标系。 
启用Z缓冲(z-buffer),你要在D3DPRESENT_PARAMETERS结构中加入: 
present.EnableAutoDepthStencil = TRUE; 
present.AutoDepthStencilFormat = D3DFMT_D16; 

这里告诉DirectX8使用16位的Z缓冲,下一步: 
pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); 
到这里Z缓冲已经设置完成。最后你还要在DrawScene()中调用清除Z缓冲内容的代码: 
pID3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0,63,0,0), 1.0, 0); 
MYVERTEX结构改成: 
struct MYVERTEX 

    FLOAT x, y, z; // The transformed position 
    DWORD color; // The vertex color 
    FLOAT tu, tv; // Texture coordinates 
}; 

在InitDirect3D()也作了相应改动,具体可见源代码。 
Direct3D中有多种矩阵,在这里只使用其中的三个:世界、视图和投影矩阵。世界矩阵变换会把正方体放在世界坐标系中,视图矩阵变换把正方体放在可视空间内,投影矩阵使正方体看起来有深度感。 
BuildMatrices()函数将建立这三个矩阵: 
void CFrameWin::BuildMatrices() 

    D3DXMATRIX matrix; 
    D3DXMatrixRotationY(&matrix, timeGetTime() / 1000.0f); 
    pID3DDevice->SetTransform(D3DTS_WORLD, &matrix); 

    D3DXMatrixLookAtLH(&matrix, &D3DXVECTOR3(0.0f, 3.0f, -5.0f), // 摄像机的空间位置 
    &D3DXVECTOR3(0.0f, 0.0f, 0.0f), // 摄象机观察点 
    &D3DXVECTOR3(0.0f, 1.0f, 0.0f)); // 摄象机向上方向矢量 
    pID3DDevice->SetTransform(D3DTS_VIEW, &matrix); 

    // 设置我们的平截面为45度角 
    D3DXMatrixPerspectiveFovLH(&matrix, D3DX_PI / 4, 4.0f / 3.0f, 1.0f, 100.0f); 
    pID3DDevice->SetTransform(D3DTS_PROJECTION, &matrix); 

运行本章的例子你将看到一个旋转的正方体。

我来说两句】 【发送给朋友】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 MFC架构下的DirectX8

 ■ [欢迎对本文发表评论]
用  户:  匿名发出:
您要为您所发的言论的后果负责,故请各位遵纪守法并注意语言文明。

最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放 / 友情链接  
Copyright ©2001-2006 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00205