// Create the primary surface with one back buffer.
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
在这个例子中,dwSize成员是DDSURFACEDESC2结构的大小.这是防止你用到的DirectDraw方法返回无效成员的错误.(dwSize是准备给将来的DDSURFACEDESC2结构的扩展用的)
dwFlags成员决定的DDSURFACEDESC2结构中那些成员将被填充有效的信息.例如在DDEx1中,dwFlags被设为你想要用DDSCAPS结构(DDSD_CAPS)和你想创建一个后台缓冲(back buffer)(DDSD_BACKBUFFERCOUNT)
dwCaps成员在例子中标示一个将要在DDSCAPS结构中使用的标志位.在这种情况下,他指定一个主平面(primary surface DDSCAPS_PRIMARYSURFACE),一个交换页(flipping surface DDSCAPS_FLIP),一个合成表面(complex surface DDSCAPS_COMPLEX).
最后,例子指定了一个后台缓冲.后台缓冲就是实际的绘图操作先在那里完成,然后,再快速的翻动(flip)到主平面(primary surface)上.在DDEx1中,后台缓冲的数目是1.其实,你要你的显存允许,你想建几个就建几个.你想知道更多的关于创建大于1块缓冲的信息,可以去看 "triple buffering".
创建的"平面"占用的存储空间,可以是系统内存也可以是显存.如果应用程序使用的空间超出了显存,DirectDraw就会使用系统内存.(例如你指定多块缓存在一个仅有1MB显存的是配器上).你也可以这样设置DDSCAPS结构的dwCaps成员,设成DDSCAPS_VIDEOMEMEORY或DDCAPS_SYSTEMMEMORY以达到只用显存或只用内存.(如指定用显存,而显存不够,IDirectDraw7::CreateSurface返回一个DDERR_OUTOFVIDEOMEMORY错误)
- 补充:
-
DDSURFACEDESC2 ddsd;
ddsd.dwSize = sizeof(DDSURFACEDESC2);dwFlags:这个域用来告诉DirectDraw,你给的数据是用来填充DDSURFACEDESC2的哪个域的。或者,如果你在一个查询操作中用这个结构,告诉DirectDraw你要获得DDSURFACEDESC2的哪个域的信息。看看表6.5,其列出了这个标志字可取的值。比如,你如果你要在 dwWidth 和 dwHeight 两个域中填入有效数据则应该像下面这样设置dwFlags域:
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT;
这样,DirectDraw便知道去查找 dwWidth 和 dwHeight 域,然后放入有效值。就把单位dwFlags看成是引导数据的指示器吧。
表 6.5. DDSURFACEDESC2的dwFlags域的各种可能的标志
值 描述
DDSD_ALPHABITDEPTH 表明 dwAlphaBitDepth 有效
DDSD_BACKBUFFERCOUNT 表明 dwBackBufferCount 有效
DDSD_CAPS 表明 ddsCaps 有效
DDSD_CKDESTBLT 表明 ddckCKDestBlt 有效
DDSD_CKDESTOVERLAY 表明 ddckCKDestOverlay 有效
DDSD_CKSRCBLT 表明 ddckCKSrcBlt 有效
DDSD_CKSRCOVERLAY 表明 ddckCKSrcOverlay 有效
DDSD_HEIGHT 表明 dwHeight 有效
DDSD_LINEARSIZE 表明 dwLinearSize 有效
DDSD_LPSURFACE 表明 lpSurface 有效
DDSD_MIPMAPCOUNT 表明 dwMipMapCount 有效
DDSD_PITCH 表明 lPitch 有效
DDSD_PIXELFORMAT 表明 ddpfPixelFormat 有效
DDSD_REFRESHRATE 表明 dwRefreshRate 有效
DDSD_TEXTURESTAGE 表明 dwTextureStage 有效
DDSD_WIDTH 表明 dwWidth 有效dwWidth:表明表面的像素宽度。当你创建一个表面是,这里便是你设定宽度的地方。320,640等等。此外,如果你要查询表面的属性,这个域将返回表面的宽度(如果你这么要求的话)。
dwHeight:表面表面的像素高度。与dwWidth类似,这里是你在创建表面时设定其高度的地方。300,240,480等等。
lPitch:这是个有趣的域。基本上它是你所选择模式的水平内存间距。看图6.8。lPitch,也被称为步幅或内存宽度,是在给定视频模式下每行的的字节数。基于如下原因,这是个非常重要的数据域:当你要求一个640×480×8的显示模式,你知道每行有640个像素,每个像素占8位内存(即1个字节)。所以,每行有640个字节,于是lPitch似乎便该设为640。对吗?不一定哦。
图 6.8. 访问一个表面技巧:lPitch将根据VRAM的不同设计而不同。故而,当你在DirectDraw表面上从一行访问另一行的内存时,你必需使用lPitch来移动到下一行,而不是用宽度乘上每像素的字节数。这一点非常之重要。
大多数新显卡支持我们所谓的“线性内存模式”而且有硬件寻址功能,这些属性已经是现实了,但并不保证每块显卡都实现之。所以,你不能假设一个640×480×8视频模式在内存中每行占640个字节。而这便是lPitch域存在的理由。你必需在你计算内存地址时应用它以保证计算正确,这样你便可以从一行移动到另一行了。比如,要访问640×480×8(256色)视频模式下的任何一个像素,你可以使用下面的代码。假设你已经从DirectDraw得到lPitch值,并且lpSurface已经指向表面内存(我会在下面解释这个参数的)
ddsd.lpSurface[x + y*ddsd.lPitch] = color;
是不是很简单啊?大多数情况下,ddsd.lPitch 设为640以代表640x480x8模式。而对于640×480×16模式,ddsd.lPitch 将设为1280(两字节每像素=640×2)。但是,对于某些显卡,出于显存的布局原因,比如内在缓存的设立或其他什么东西,就使得事情不像上述这样了。所以最正规的方式是:在计算内存时总是使用lPitch,你便总是安全的。
技巧:尽管lPitch值并不总是等于你设置的视频模式的水平值,但使用其来测试水平值可以使你能够调用到其他优化函数。比如,在你完成初始化部分功能的代码中,你可以去获得lPitch值并与你选择的视频模式水平值比较。如果它们相等,则你可以切换到你为优化程序而硬编码每行字节数的函数上。
lpSurface:这个域获得指向你随创建表面的真实内存地址的指针。这些内存可能是VRAM也可能是系统内存,但是你无需为次担心。一旦你获得了指向该内存的指针,你便可以像操作其他内存一样操作它了,比如向它写数据或读数据,等等,这完全取决于你想如何填充像素。呵呵,让这个指针有效多容易啊!但是我们还是要在这里多停留一会。一般,你必需“锁定”表面内存,并且告诉DirectX你要在该内存上面工作了而其他的进程不许试图在该内存上读或写。进一步的,当你获得了这个指针时,根据不同的色深(8,16,24,32)你要经常对其进行类型转换并将其复值给一个工作指针。
dwBackBufferCount:这个域被用来设置和读取后备缓存(或与主表面关联的副离屏翻页缓存)的数目。如果你能回忆起来,通过创建一个或更多的虚主表面(与表面拥有同样的图样和色深的缓存),后备缓存可用来实现动画的平滑化,这也便是离屏缓存。然后你在后备缓存上绘图,这个后备缓存对于用户而言是不可见的。接着快速的翻页或拷贝后备缓存到主表面以供显示。如果你只有一个后备缓存,这个技术便成为“双缓存技术”。使用两个缓存便叫“三缓存技术”,当然后者比前者拥有更好的效果但也占用更多的内存。为了是事情简单点,大多数情况下,你将创建一个包括一个主表面和一个后备缓存的翻页链。
ddckCKDestBlt:这个域被用来控制目标颜色键。当进行块传输操作时,这个域控制写入颜色的方式。更多信息将在后面第七章“高级DirectDraw和位图图形”上介绍。
ddckCKSrcBlt:这个域表明源颜色键。即当你进行bitmapping操作时{?后面好像有这个术语,一时想不起来了,但翻到后面再该过来吧。yew98}你不想被块传递的颜色。这是一个你如何设置你位图透明色的的方法。详见第七章。
ddpfPixelFormat:这个域用来获得表明像素的格式。当你去查询表明的属性是这就非常重要了。下面的是其结构。你可能要去查询DirectX SDK以获得更多的细节信息。因为这些信息实在太多了,而且和现在的讨论关心也不大。
typedef struct _DDPIXELFORMAT
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwFourCC;
union
{
DWORD dwRGBBitCount;
DWORD dwYUVBitCount;
DWORD dwZBufferBitDepth;
DWORD dwAlphaBitDepth;
DWORD dwLuminanceBitCount; // new for DirectX 6.0
DWORD dwBumpBitCount; // new for DirectX 6.0
} DUMMYUNIONNAMEN(1);
union
{
DWORD dwRBitMask;
DWORD dwYBitMask;
DWORD dwStencilBitDepth; // new for DirectX 6.0
DWORD dwLuminanceBitMask; // new for DirectX 6.0
DWORD dwBumpDuBitMask; // new for DirectX 6.0
} DUMMYUNIONNAMEN(2);
union
{
DWORD dwGBitMask;
DWORD dwUBitMask;
DWORD dwZBitMask; // new for DirectX 6.0
DWORD dwBumpDvBitMask; // new for DirectX 6.0
} DUMMYUNIONNAMEN(3);
union
{
DWORD dwBBitMask;
DWORD dwVBitMask;
DWORD dwStencilBitMask; // new for DirectX 6.0
DWORD dwBumpLuminanceBitMask; // new for DirectX 6.0
} DUMMYUNIONNAMEN(4);
union
{
DWORD dwRGBAlphaBitMask;
DWORD dwYUVAlphaBitMask;
DWORD dwLuminanceAlphaBitMask; // new for DirectX 6.0
DWORD dwRGBZBitMask;
DWORD dwYUVZBitMask;
} DUMMYUNIONNAMEN(5);
} DDPIXELFORMAT, FAR* LPDDPIXELFORMAT;
注意:我加粗的域是常用域ddsCaps:这个域用来使那些被要求的但尚未在表面属性中定义的项有效。事实上,这个域又是另一个数据结构。下面显示了DDSCAPS2:
typedef struct _DDSCAPS2
{
DWORD dwCaps; // Surface capabilities
DWORD dwCaps2; // More surface capabilities
DWORD dwCaps3; // future expansion
DWORD dwCaps4; // future expansion
} DDSCAPS2, FAR* LPDDSCAPS2;
在99.9%的情况下,你只需设置该结构的第一个域。dwCaps.dwCaps2 是为3D准备的,而其他域dwCaps3 和 dwCaps4是为未来扩展之用,尚未使用。总之,表6.6列出了dwCaps可能设置的标志值。要看完整的列表,到DirectX SDK里去。比如当要创建一个主表面是,你可以像下面这样设置ddsd.ddsCaps
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
我知道上面这种表达方式很复杂,在某种程度上确实如此。双重嵌套的控制标志确实有点痛苦。但是,忍受吧……
表 6.6. DirectDraw表面的属性控制设置
值 描述
DDSCAPS_BACKBUFFER 表明这个表面是表面翻页结构中的后备缓存。
DDSCAPS_COMPLEX 表明是一个复习表面。一个复杂表面是一个与一或多个串成翻页链的后备缓存关联的主表面。
DDSCAPS_FLIP 表明这个表面是一个表面翻页结构中的一部分。但这个属性被传递给 CreateSurface() 方法时, 一个前端缓存和一个或多个后备 缓存将被创建。
DDSCAPS_LOCALVIDMEM 表明这个表面优先存在于显存中。如果这个标志选中则 DDSCAPS_VIDEOMEMORY 也必需选中。
DDSCAPS_MODEX 表明这个表面是一个320x200 或 320x240 的Mode X 表面。
DDSCAPS_NONLOCALVIDMEM 表明这个表面优先存在于非本地显存中。如果这个标志选中则 DDSCAPS_VIDEOMEMORY 也必需选中。
DDSCAPS_OFFSCREENPLAIN 表明这个表面是个离屏表面。这样该表面便不能是某种特殊表面了,比如不是一个覆盖层,素材,z序,前端缓存,后备缓存,或者 alpha 表面。(Usually used for sprites。)
DDSCAPS_OWNDC 表明这个表面将长期与一个设备上下文关联。
DDSCAPS_PRIMARYSURFACE 表明这个表面是主表面。其描述了此刻为用户所见的东西。
DDSCAPS_STANDARDVGAMODE 表明该表面是一个标准的VGA模式的表面,而非 Mode X 模式。这个标志不能与 DDSCAPS_MODEX 标志同时使用。
DDSCAPS_SYSTEMMEMORY 表明这个表面创建在系统内存中。
DDSCAPS_VIDEOMEMORY 表明这个表面创建在显存中。
版权声明:本文为博主原创文章,未经博主允许不得转载。