关键字:离屏表面 色彩键
1.前情总结
至此,已经学习在显存中创建主显示表面(primarySurface)、备用缓冲表面(backSurface),以及在使用双缓冲的时候,在系统内存中创建的double_buffer。
使用double_buffer的时候,通过现将内容渲染到double_buffer,在blit到primarySurface,获取平滑的图像切换(不会看到绘制的过程);
使用backSurface的时候,既可以通过blt进行内存的拷贝,也可以使用页面切换,直接交换主显示表面和备用缓冲表面。
其中,创建备用缓冲表面的时候,需要创建复杂主显示表面(DDSCAPS_COMPLEX),并且,通过获取附加(GetAttachedSurface)后备表面的方式得到备用缓冲表面。这里,得到的附加表面是可以用于页面切换的。
2.离屏表面
为什么需要离屏表面?
在系统内存或者显存中创建离屏表面,有了离屏表面,才能堆砌位图,而后利用blitter将它们blit到屏幕。
即,当读取了bmp文件后,将位图像素渲染至离屏表面之后,就可以释放bmp文件所占内存了。bmp文件中的buffer中保存的像素信息对于引擎来说是没有用的。
之后,可以使用blitter将任意我们需要的sprite或者说是图像Rect blit到显示表面。
2.1 创建离屏表面
创建离屏表面和创建主显示表面几乎是一样的,都是使用LPDIRECTDRAW7::CreateSurface()进行创建。(DirectDraw创建表面)
区别在于,因为我们创建的不是主显示表面,因此,在创建表面的描述信息(DDSURFACEDESC2)中,需要做不同的设置:1
2
3
4
5
6
7
8
9
10
11
12
13DDSURFACEDESC2 ddsd; // 表面描述嘻嘻
LPDIRECTDRAWSURFACE7 lpdds; // 临时表面指针
DDRAW_INIT_STRUCT(ddsd);
// 设置起作用的字段DDSD_WIDTH /DDSD_HEIGHT 表面的宽度/高度(像素)
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = width;
ddsd.dwHeight = height;
// surface的能力是DDSCAPS_OFFSCREENPLAIN离屏表面,mem_flags是内存位置。0表示显存,1表示系统内存。
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
其中,mem_flags表示表面创建的位置,0表示显存,1表示系统内存。但是,如果显存不够,会将表面创建到系统内存。
创建离屏表面的完整函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40// 创建离屏表面
LPDIRECTDRAWSURFACE7 DDraw_Create_Surface(int width, int height, int mem_flags, int color_key = 0)
{
DDSURFACEDESC2 ddsd; // working description
LPDIRECTDRAWSURFACE7 lpdds; // temporary surface
// set to access caps, width, and height
DDRAW_INIT_STRUCT(ddsd);
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.dwWidth = width;
ddsd.dwHeight = height;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | mem_flags;
if (FAILED(lpdd->CreateSurface(&ddsd, &lpdds, NULL)))
return(NULL);
if (color_key >= 0)
{
DDCOLORKEY color_key;
if (SCREEN_BPP == 8)
{
color_key.dwColorSpaceLowValue = 0; // 从Low到High都是透明键
color_key.dwColorSpaceHighValue = 0;
}
else
{
color_key.dwColorSpaceLowValue = __RGB16BIT565(0, 0, 0); // 从Low到High都是透明键
color_key.dwColorSpaceHighValue = __RGB16BIT565(0, 0, 0);
}
lpdds->SetColorKey(DDCKEY_SRCBLT, &color_key);
} // end if
// return surface
return(lpdds);
} // end DDraw_Create_Surface
3.色彩键(ColorKey)
当我们将离屏表面的Sprite blit到显示表面的时候,可以选择一个色彩范围,不被blit到目标。
DDCOLORKEY:1
2
3
4
5
6
7
8
9
10
11
12/*
* DDCOLORKEY
*/
typedef struct _DDCOLORKEY
{
DWORD dwColorSpaceLowValue; // low boundary of color space that is to
// be treated as Color Key, inclusive
DWORD dwColorSpaceHighValue; // high boundary of color space that is
// to be treated as Color Key, inclusive
} DDCOLORKEY;
typedef DDCOLORKEY FAR* LPDDCOLORKEY;
表示从dwColorSpaceLowValue到dwColorSpaceHighValue的颜色都为透明色。
如果是8位深度,是两个index,否则是两个RGB颜色值。
为表面设置色彩键有两种方式:一种是创建表面的时候就指定,另外一种是设置表面的色彩键
- 创建表面的时候就指定的时候,在表面描述结构(DDSURFACEDESC2)中:
1
2
3
4DDSURFACEDESC2 ddsd;
DDRAW_INIT_STRUCT(ddsd);
...
ddsd.dwFlags = ...| ... | DDSD_CKSRCBLT;
上述例子中,ddsd指定了DDSD_CKSRCBLT字段起作用,之后再设置ddsd.ddckCKSrcBlt.dwColorSpaceLowValue和ddsd.ddckCKSrcBlt.dwColorSpaceHighValue。
- 在创建表面之后,设置表面的色彩键:使用DDCOLORKEY结构描述色彩范围,然后调用 LPDIRECTDRAWSURFACE7::SetColorKey();
1 | LPDIRECTDRAWSURFACE7 lpdds; |
3.1 源色彩键
source中的色键色彩不被blit到目标。
- 描述表面能力时候的色彩键标志:
表面能力的色彩键标志
值 | 描述 |
---|---|
DDSD_CKSRCBLT | 表面描述的ddckCKSrcBlt成员有效,包含源色彩键的色彩键信息 |
DDSD_CKDESTBLT | 表面描述的ddckCKDestBlt成员有效,包含目标色彩键的色彩键信息 |
DDSD_CKSRCOVERLAY | 表面描述的ddckCKSrcOverlay成员有效,包含源叠加色彩键的色彩信息 |
DDSD_CKDESTOVERLAY | 表面描述的ddckCKDestOverlay成员有效,包含目标叠加色彩键的色彩信息 |
- 表面SetColorKey()的有效标志:
表面SetColorKey()的有效标志
值 | 描述 |
---|---|
DDCKEY_COLORSPACE | 描述一个色彩空间。在此色彩空间内的值才会被blit |
DDCKEY_SRCBLT | 源色彩键 |
DDCKEY_DESTBLT | 目标色彩键 |
DDCKEY_SRCOVERLAY | 叠加源色彩键 |
DDCKEY_DESTOVERLAY | 叠加目标色彩键 |
3.2 目标色彩键
如果目标位置的色彩是色键色彩,source中的色彩不被blit到目标。
3.3 其他
目标色彩键只在HAL(硬件抽象层)可用,在HEL中不行。
叠加色彩键用于视频处理。详情参见DirectX SDK.