如何设定储藏表面,用来存放图片
这个也很简单,你如果需要表面来存储图片,必须使用IDirect3DSurface8,嘿嘿,现在可以看出来DirectDraw现在根本没有用了吧?现在给你我找到的问题,使用Direct3D8进行2D图形显示,并不是很好,特别是模仿DirectDraw有关的工序。这个先不说,先讲讲如何建立这个IDirect3DSurface8界面对象。
首先你要定义一个指针:
IDirect3DSurface8 * m_pD3DSurface;
然后,你要建立这个表面,下面的代码可以证明建立一个表面是多么简单:
HRESULT hRet = pDevice->CreateImageSurface(img_size_x, img_size_y,
D3DFMT_X8R8G8B8, &m_pD3DSurface);
if (FAILED (hRet))
{
return hRet;
}
四个参数很容易理解吧?第一个是表面的长,第二个是表面的宽,第三个是表面的像素深度,最后一个是返回的表面指针。是不是很简单?
然后你要将图片载入表面,所需工序也很简单:
return D3DXLoadSurfaceFromFile(m_pD3DSurface,
NULL,
NULL,
fn,
NULL,
D3DX_DEFAULT,
col_key,
NULL);
很简单吧,这个函数是Direct3D扩展库里的帮助函数,可以用来提取各种各样的图像文件格式,象BMP,JPG,GIF,PCX,等等。你不仅能从文件里载入图片,还能从内存中载入图片文件,甚至能从内存中载入图片,这些函数是:
D3DXLoadSurfaceFromFile()
D3DXLoadSurfaceFromFileInMemory()
D3DXLoadSurfaceFromMemory()
D3DXLoadSurfaceFromResource()
D3DXLoadSurfaceFromSurface()
这些都在d3dx8.h里面,我用的是第一个函数,D3DXLoadSurfaceFromFile()。这个函数所需的参数很多,第一个是载入表面的指针,第二个是指向调色板的指针,这个主要是用于象素为八位的图形格式,不知道谁还用这个,所以,我个人觉得没用,我给了NULL,第三个参数定义表面上你想要存储图像的长方形,我只定义整个表面的,所以不需要定义长方形,给它NULL。第四个是图像文件的文件名。第五个是图形文件中的你想要的长方形,我想载入整个文件,所以给它NULL。第六个是载入文件时进行过滤的风格,我用的是最慢的一种,D3DX_FILTER_TRIANGLE | D3DX_FILTER_DITHER。还有其他风格你可以使用,这里就不多介绍,通过微软文档,你可以了解这些风格的使用方法。然后你定义透明色,这个颜色用来定义绘画时被忽略的颜色,这个颜色是D3DCOLOR。
我前面没有介绍D3DCOLOR,D3DCOLOR就是DWORD,四个字节。第一个字节是颜色的透明度,0x0(0)表示完全透明,0xFF(255)表示完全不透明;第二个字节是红色的深度,0x0是最浅,0xFF 是最深;第三个字节是绿色的深度,0x0是最浅,0xFF是最深;第三个字节是蓝色的深度,0x0是最浅,0xFF是最深。
举例:0xFF000000才是表示漆黑色。0x00000000不是漆黑色。
最后一个参数是指向一个D3DXIMAGE_INFO,你可以定义这个参数,然后调入函数,也可以设定为NULL,这个参数是调入返回型,也就是说你给定了一个变量,调入后,如果函数运行成功,这个变量的数据会改变并返回。
将储藏表面上的画面贴到背景表面上,然后翻页
做到这一步其实也很简单,但是功能很有限,所以我不喜欢用DirectDraw风格的进行贴图。IDirect3DDevice8只给你提供了一个函数,叫CopyRect(),这个函数只能进行原图贴图,不能扩大缩小贴图,也不能使用透明色贴图,所以我很失望。
实现这一步很容易,第一是获得背景表面的指针,这是你要贴的目标表面,原表面是你的储藏表面。得到背景表面后,使用IDirect3DDevice8::CopyRect来将你要的图片长方形贴到背景表面上。我们来看看具体的操作:
HRESULT D3DDrawHelper::Draw(IDirect3DSurface8 * pSurface,
const RECT * p_src_rect,
const POINT * p_dest_pt)
{
if (pSurface == NULL
|| p_src_rect == NULL
|| p_dest_pt == NULL)
return E_FAIL;
IDirect3DSurface8 * pBackBuffer;
HRESULT hRet = m_pD3DDevice->GetBackBuffer(0,
D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
if (FAILED (hRet))
{
::MessageBox(NULL, "Failed 1", "ERROR", MB_OK);
return hRet;
}
hRet = m_pD3DDevice->CopyRects(pSurface,
p_src_rect,
1,
pBackBuffer,
p_dest_pt);
if (FAILED (hRet))
{
if (hRet == D3DERR_INVALIDCALL)
::MessageBox(NULL, "Failed 2", "ERROR", MB_OK);
return hRet;
}
return S_OK;
}
首先是获得背景表面,也就是使用IDirect3DDevice8::GetBackBuffer,这个函数需要3个参数,第一个是背景表面的下标,这里的原因是,你可以拥有多于一个的背景表面,所以需要一个下标来获取你所需要的背景表面。第二个是表面的样式,这个只有一和有效数值D3DBACKBUFFER_TYPE_MONO,因为D3DBACKBUFFER_TYPE_STEREO在IDirect3D8里是不支持的。
下一个函数是CopyRect,将一块表面上的图像长方形贴到另一块表面上。这个函数的长处是,你可以定义好多不同的长方形于一个数组,然后,定义你的长方形的数量,CopyRect会自动替你重复贴图。将一连串的长方形图像从一个表面贴到另一表面上。
但是,这个函数不支持透明色,不支持扩大缩小图像,所以使用这个函数能做到的功能很小,先谈谈它所需要的参数,第一个是存储表面的指针,从这个表面,图像长方形被贴到目标表面上。第二个是长方形数组,这个数组定义原图上需要的长方形。第三个是数组大小,我直接用和一个长方形,所以数组大小只是一。第四个是目标表面,第五个是目标表面的点数组,这个数组是个和前面说的长方形数组是平行的,数组的大小和前面的也是一样的,之所以使用点是因为长方形数组已经定义了长方形的大小。
好了,到这里,你就能进行翻页了,怎么翻页呢?前面说到的IDirect3DDevice8::Present()就是用来进行这样的操作。
下次讲讲如何超越这个局限达到更好的2D图形特效。