这个教程集中于一个方面,就是如何更快更直接地显示图像,微软提供了一个COM界面,专门用来进行这样的操作,而且效率比自己设计低端显示函数要快得多。
你需要的界面
微软提供了一个简单的精灵界面,这个界面叫ID3DXSprite,这个界面里的一个函数做到所有你需要的2D显示操作。你可以猜得到,这个函数叫Draw(),在调用这个函数之前,你必须调用Begin(),画完后你必须调用End()。
还有一个界面你必须用的,是IDirect3DTexture8,这个界面很像IDirect3DSurface8,是用来存放图片的,而且,你要是仔细阅读微软的帮助文档,你会发现IDirect3DTexture8使用IDirect3DSurface8。这个界面可以做很多比较有意思的3D图像显示,在3D世界里,Texture,纹理是用来覆盖几何形装达到色彩斑斓的真实3D物体显示。将深度去掉,就是2D,所以纹理轻易可以用到2D图形程序设计中。
建立ID3DXSprite界面对象
这个很容易做到。首先,要运用ID3DXSprite,必须用到到“d3dx8.h”和“d3dx8.lib”,建立一个ID3DXSprite界面,你只要调用函数D3DXCreateSprite就可以了。这个函数需要IDirect3DDevice8界面指针。
hRet = D3DXCreateSprite(m_pD3DDevice, &m_pD3DXSprite);
if (FAILED (hRet))
{
::MessageBox(hWnd,
"ERROR: Failed to acquire ID3DXSprite instance.",
"ERROR", MB_OK);
return hRet;
}
最后一个参数是返回的ID3DXSprite指针对象。是很简单吧?这个函数调用可以在我修改后的d3d_draw_helper.cxx里找到。当然我在d3d_draw_helper.h里加了一个新的成员。
解释一下纹理
纹理就是一张图没什么特别的,在8.0以前,设计者必须建立表面来储存纹理,现在,存储纹理可以用专门的类。这个类就是IDirect3DTexture8。
将一张图载入一个纹理界面,DirectX也提供了一些帮助函数,方便设计者。者这些函数是:
D3DXCreateTexture ()
D3DXCreateTextureFromFile ()
D3DXCreateTextureFromFileEx ()
D3DXCreateTextureFromFileInMemory ()
D3DXCreateTextureFromFileInMemoryEx ()
D3DXCreateTextureFromResource ()
D3DXCreateTextureFromResourceEx ()
我所使用的函数是第三个,D3DXCreateTextureFromFileEx()。这个函数替你建立一个纹理对象,然后载入一个图像文件。在处理2D图形程序设计时,我最喜欢的函数是D3DXCreateTextureFromFileInMemoryEx(),这个函数给你很多空间。在这里现不多谈这个。
看看我是如何使用D3DXCreateTextureFromFileEx ()这个函数
HRESULT D3DTextureHelper::LoadTexture(IDirect3DDevice8 * pDevice,
const char * fn)
{
return D3DXCreateTextureFromFileEx(
pDevice,
fn,
D3DX_DEFAULT,
D3DX_DEFAULT,
1,
0,
D3DFMT_UNKNOWN,
D3DPOOL_MANAGED,
D3DX_DEFAULT,
D3DX_DEFAULT,
0xFF000000,
NULL,
NULL,
&m_pD3DTexture);
}
第一个参数调入是IDirect3DDevice8对象指针。第二个参数是文件名。第三个,第四个是图像的长和宽。第五个是MipLevel,我调入1,表示MipLevel是一层,MIP使用来平滑3D图像远景显示中出现的杂乱线条的问题。在2D图像程序设计中,我觉得是没什么用,所以,我就设定为一,也就是说这个层只有一层。第六个参数设定这个纹理的使用方法,这个参数可以是0,D3DUSAGE_RENDERTARGET,和D3DUSAGE_DYNAMIC。我使用的是0。你也可以使用了D3DUSAGE_DYNAMIC,这样可以动态改变纹理中的数据。如果你纹理不需要动态性改变,就不需要设定这个参数为D3DUSAGE_DYNAMIC。第七个参数是纹理的格式,就是像素深度格式,你可以自己定义,也可以直接定义为D3DFMT_UNKNOWN,让程序在载入图像文件时定义象素深度。第八个是POOL,这是如何管理这些纹理。我使用D3DPOOL_MANAGED,设定这个你必须设定使用方法为0,不能使用D3DUSAGE_DYNAMIC。然后第九个参数是图像像素的过滤方式,我选择系统自定义的,第十个是MIP的像素过滤方式,我也选择系统自定义。第十一个参数是透明色,设定这个颜色,在显示时,这图像中的这个颜色将忽略。第十二个参数可以用来定义图像文件的内部信息,这个参数是进出型,你可以定义一个数据结构对象,初始化里面的数据定义图像文件的信息。你也可以调入NULL,这样,你就不在乎返回值。接下来是调色板信息,这个只工作于8位图像文件上,我调入NULL,表示不用调色板信息。最后是纹理返回的指针。简单吧?
这里要说明的是,纹理的长宽不是随便大小都可以,长和宽必须是2的n次方,比如1,2,4,8,16,32,....某些显卡可以支持任何数值的长和宽,但是多数显卡支持的是2的n次方为大小的纹理。
如何显示纹理
没有ID3DXSprite,你就必须使用Vertex,和IDirect3DDevice8的DrawPrimitive来实现。有了ID3DXSprite,这个操作就简化了许多。我们早就建立了ID3DXSprite的界面对象,现在我们来画纹理。
HRESULT D3DDrawHelper::DrawTexture(IDirect3DTexture8 * pTexture,
const RECT * p_src_rect,
const POINT * p_dest_pt)
{
HRESULT hRet = m_pD3DXSprite->Begin();
if (FAILED(hRet))
{
return hRet;
}
D3DXVECTOR2 tex_pos;
tex_pos.x = (float)p_dest_pt->x;
tex_pos.y = (float)p_dest_pt->y;
hRet = m_pD3DXSprite->Draw(
pTexture,
p_src_rect,
NULL,
NULL,
0,
&tex_pos,
0xFFFFFFFF);
if (FAILED(hRet))
{
m_pD3DXSprite->End();
return hRet;
}
m_pD3DXSprite->End();
return S_OK;
}
可以看出画图像在这里也很简单,第一,你调用ID3DXSprite::Begin(),这一不你要检查是否出错,如果出错,就没有必要继续下一步,接着你调用ID3DXSprite::Draw(),这个函数很有意思,调整你的输入参数,你可以实现不少简单特效。先解释一下参数。第一个是指向一块纹理的指针。第二个是指定你所要显示的图文上的长方体。第三个是一个矢量,二元矢量,这个矢量是用来定义纹理放大缩小的值。也就是说,你定义一个D3DXVECTOR2,里面的x,y定义成1.5f,这就是说你希整个纹理在显示被放大1.5倍。第四个也是一个二元矢量,这是用来定义纹理旋转的中心。接下来参数是的你希望纹理旋转的角度。这个和前一个参数是配合,用来旋转纹理。自己随便修改一下参数值看看效果如何?下一个是你要定义的纹理定位的左上角的位置,这也是一个二元矢量。最后一个是显示的颜色,这个参数可以用来搞一些更有意思的特效,调入0xFFFFFFFF,原来的图像不变地显示出来,如果你把数值变为0x88FFFFFFFF,纹理的显示将是原图的半色,这就是最标准的淡入淡出的AlphaBlending。要是在DirectDraw底下你必须写很多代码来实现这个,使用Direct3D8,就不用走这么多歪路。还有,如果你把数据改成0xFFFF0000,你会发现整个纹理的覆盖色是深红。
好了到这里你学到了最基本的2D图形程序设计,这是简化型的图形显示操作,自己整理后可以方便地显示2D图像,设计效率很高的2D游戏。