您现在的位置:首页 >> 图形媒体 >> 图形媒体 >> 内容

使用D3D8实现2D图形显示技术一(1)

时间:2011/9/3 15:03:10 点击:

  核心提示:DirectDraw已经死了,所以为什么还要用DirectDraw?从DirectX8.0开始,微软提供了3D技术可以直接用于2D图形程序设计。你可以注意到DirectDraw7的有关文档从Direc...


DirectDraw已经死了,所以为什么还要用DirectDraw?从DirectX8.0开始,微软提供了3D技术可以直接用于2D图形程序设计。你可以注意到DirectDraw7的有关文档从DirectX的文档中取消了。

当然2D图形程序设计还是可以实现,使用现有的3D图像技术,更多的2D特效能在轻易实现,这个教程不会给你任何特效,只是给你最基本的2D图形显示概要。

章节概要
这个教程是不完全的,因为我用的是IDirect3D8做范例,最后才发现某些东西并不使是我想象的那么好,因为有些和DirectDraw类似的东西并不是我想象的那样,Direct3D9界面中很多东西正是我想要的,但是下次再说这个。

微软的帮助文件
微软的帮助文件,象DirectDraw7,DirectX8.0,DirectX8.1,还有DirectX9.0,可以在这里找到http://msdn.microsoft.com/archive/,英文的,没办法。

所需头文件
在写码之前,你必须包括些头文件。两个头文件是最常用的,所以我在需要这两个头文件的源码中加入这个。

#include <d3d8.h>
#include <d3dx8.h> 

IDirect3D8界面
如果要使用Direct3D8,你就必须先建立IDirectD8界面对象。不同于DirectDraw,和其他早期的D3D界面那样。用起来很麻烦,现在,只需要简单的一句就能建立IDirect3D8界面对象。

m_pD3D = Direct3DCreate8(D3D_SDK_VERSION);
if (m_pD3D == NULL)
{
::MessageBox(hWnd,
"ERROR: Failed to acquire IDirect3D8 interface instance.",
"ERROR", MB_OK);
return E_FAIL;

D3D_SDK_VERSION是什么,是一个常量,用来保证建立D3D界面时使用的DirectX头文件版本是正确版本。这个在微软的文档中都有定义。下一步是定义或是提取一个IDirect3DDevice8界面对象的指针,用这个指针来初始化显示,建立主表面和背景表面。

建立IDirect3DDevice8界面对象
在建立这个界面之前,你必须测试电脑硬件是否支持你要建立的显示模式。所谓显示模式有两种定义,一是视窗程序模式,你写的程序在一个视窗里运行。另一种就是常用的全屏模式。前一种格式,显示格式依赖于系统设定的显示模式,也就是说,你把桌面设定为1024X768X16,你可以设定你自己的应用程序视窗的长宽,但是不能改变你视窗程序的像素深度。如果你使用全屏模式,你可以设定长宽和象素深度,你还是需要测试硬件对你的设定是否支持。

做到这一点其实很容易,进入Direct3D8以后,这些比较麻烦的操作都变得简单了,首先你要做的,是调用GetDisplayMode这个函数,我是这么做的

D3DDISPLAYMODE display_mode;
HRESULT hRet = m_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,
&display_mode);
if(FAILED(hRet))
{
::MessageBox(hWnd,
"ERROR: Failed to acquire current display mode.",
"ERROR", MB_OK);
return hRet;

调用这个函数返回D3DDISPLAYMODE数据结构,这里面的数据可以用来进行你的测试。看看这个结构中的数据:

typedef struct _D3DDISPLAYMODE {
UINT Width;
UINT Height;
UINT RefreshRate;
D3DFORMAT Format;
} D3DDISPLAYMODE; 
 

前面两个很容易,是你的桌面的长宽,第三个是屏幕刷新率,最后一个像素的深度,这是一个自定义的数据,enum type。在我的程序中,我只是简单地比较这个数据来测定现有的桌面像素深度,就这样:

// OK I want 32Bit color depth in the format of X8R8G8B8.
if (display_mode.Format != D3DFMT_X8R8G8B8)
{
// All right, now you tell the user to change their display mode,
::MessageBox(hWnd,
"ERROR: Display Resolution is not up to spec. Pixel resolution should be 32bit.",
"ERROR", MB_OK);
return hRet;

D3DFMT_X8R8G8B8的定义是,表面的象素深度是4字节,最左边的字节是未知象素深度,接下来是红色像素深度,绿色像素深度,和蓝色像素深度。其他数据还有D3DFMT_A8R8G8B8,D3DFMT_R8G8B8,D3DFMT_R5G6B5等等等。我这种做法其实是一种白痴懒汉的做法,真正的做法是再调用CheckDeviceFormat来确定硬件是否支持你的主表面和背景表面格式。还有EnumAdapterModes来给你硬件所支持的一系列的显示格式。

下一步是建立IDirect3DDevice8界面对象,你需要初始化一个数据结构,这个数据结构是用于定义显示模式,这个结构是D3DPRESENT_PARAMETERS,主要的目的2D图形显示,所以这个结构中很多数据你都不用定义。我的定义是:

ZeroMemory(&m_d3dpp, sizeof(m_d3dpp));
// Throw away previous frames, we don't need them
m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
m_d3dpp.hDeviceWindow = hWnd;
//We only need a single back buffer
m_d3dpp.BackBufferCount= 1; 
// even though you uses windowed mode, we can still
// set the backbuffer width and height.
m_d3dpp.BackBufferWidth = 640;
m_d3dpp.BackBufferHeight = 480;

m_d3dpp.Windowed = TRUE;
m_d3dpp.BackBufferFormat = display_mode.Format;
m_d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;

hRet = m_pD3D->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, // we want full hardware support.
hWnd,
// we are not doing vertex processing.
D3DCREATE_MIXED_VERTEXPROCESSING,
&m_d3dpp,
&m_pD3DDevice);
if(FAILED(hRet))
{
::MessageBox(hWnd,
"ERROR: Failed to acquire IDitect3DDevice instance.",
"ERROR", MB_OK);
return hRet;
}
 

看看我都定义了些什么。首先是D3DPRESENT_PARAMETERS::SwapEffect,我定义为D3DSWAPEFFECT_DISCARD,也就是每次的表面翻页后,背景表面的数据都给丢弃。

然后我定义D3DPRESENT_PARAMETERS::hDeviceWindow为程序的视窗ID,也就是程序视窗的HWND数值。

D3DPRESENT_PARAMETERS::BackBufferCount定义背景表面的数量,我设定这个为1。

虽然我设计的这个例程是视窗模式,但是主表面的长宽还是可以定义的。所以我将主表面和背景表面的大小定义为640X480。

然后,我定义显示方式为视窗显示模式,然后设定背景显视模式为X8R8G8B8,看来我前面说的是错的,你在视窗模式下可以定义像素的深度。我只是没有进一步考证这个问题。

最后也是最重要的一步是定义
D3DPRESENT_PARAMETERS::Flags数据为D3DPRESENTFLAG_LOCKABLE_BACKBUFFER,这么做的原因是,如果步定义这个,你就无法直接将数据写上背景表面上。所有DirectDraw能进行的工序都做不了。

到这里了,最后一道工序是调用IDirect3D8的CreateDevice函数,第一个参数是主显卡的ID,这个数值永远是D3DADAPTER_DEFAULT,第二个参数是视窗的ID,也就是视窗的HWND数值。第三个参数设定3D顶点的处理方式,也就是用硬件处理还是软件处理,还是混合,因为我们的程序中可能回会用道这个,我把它设定为D3DCREATE_MIXED_VERTEXPROCESSING。第四个参数是我定义的D3DPRESENT_PARAMETERS结构地址,最后是返回IDirect3DDevice8的地址。只要所有的函数调用都没有问题,到此为止,所有的初始化步骤完成。

如何清理背景表面
这个很简单,你只要这么做:

m_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); 

Clear是专门用来清理表面,用于做显示前的前期准备。第一个参数是指定多少个长方形需要清理,第二个是一个指针指向一个长方体数组,第一个参数就是定义这个数组的大小。第三个参数定义清除的目标,我将这个设为D3DCLEAR_TARGET,还有两个不同的常量,D3DCLEAR_STENCIL和D3DCLEAR_ZBUFFER,都是和3D图形程序设计有关,我在这里只考虑2D有关的东西,所以这两个常量是没用的。第四个参数是填上表面的颜色,我定义为漆黑色,第五个是Z值,0.0是深度离盯着屏幕的观众最近,1.0是最远,这里任何数值都无所谓,所以我用1.0。最后一个是Stencil数值,这个也无所谓,所以我给它0。

如何显示准备好的背景表面
这个也会很简单,只要这么做就可以了:

m_pD3DDevice->Present(NULL, NULL, NULL, NULL); 

这个函数需要四个参数,第一个是原表面的长方形,如果是整个视窗显示,NULL就够了。第二个是目标表面的长方形,如果是全视窗更新,调入值也是NULL。第三个,告诉IDirect3DDevice你想要显示的视窗HWND数值。这个,你在前面早就定义,就是你在D3DPRESENT_PARAMETERS::hDeviceWindow值,除非你想将画面贴到不相关的视窗上,你只要调入NULL就可以。最后一个根本没有用,所以调入NULL。

上一页123下一页

作者:网络 来源:转载
共有评论 0相关评论
发表我的评论
  • 大名:
  • 内容:
本类推荐
  • 没有
本类固顶
  • 没有
  • 盒子文章(www.2ccc.com) © 2024 版权所有 All Rights Reserved.
  • 沪ICP备05001939号