DirectDraw用到的DDSURFACEDESC2

简介: <strong>DDSURFACEDESC2</strong> 结构定义一个需求的平面.下面的例子演示了结构的定义和标志位的设定: <br> // Create the primary surface with one back buffer.  <br> ZeroMemory(&ddsd, sizeof(ddsd)); <br> ddsd.dwSize = sizeof(d
DDSURFACEDESC2 结构定义一个需求的平面.下面的例子演示了结构的定义和标志位的设定:
// 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    表明这个表面创建在显存中。

相关文章
|
程序员 C++ Windows
GDI+与GDI屏幕抓图比较
GDI+与GDI屏幕抓图比较
165 0
C#编程-128:GDI绘图基础知识
C#编程-128:GDI绘图基础知识
C#编程-128:GDI绘图基础知识
MFC中MessageBeep与sndPlaySound播放声音函数使用
MessageBeep(0x00000000L);        //用来播放系统默认音频文件,如0x00000000L为系统提示音,具体音频对应规则,请参照MSDN。   sndPlaySound函数用来播放指定音频WAV文件,分为两种: 同步模式:音乐播放过程中函数不返回,播放完成才返回 异步播放在做游戏等需要播放时间较长的音乐时使用,因为程序不会在音乐播放过程中有假死的情况。
2657 0
directdraw显示yuv视频,出现屏保时,yuv显示不出来,表面丢失
原因是: DDrawSurface 丢失, DDraw表面在很多情况下都会丢失(如:启动其他全屏独占程序,屏保,或锁屏时), 表面丢失其实就是表面所使用的内存或显存被DirectDraw系统释放, 分配给其他程序. 如果表面丢失, 对此表面的操作都会返回 DDERR_SURFACELOST , 此时应该调用 IDirectDrawSurface 接口方法 Restore 来恢复表面(重新申请内存或显存)。
1153 0
directdraw的多画面显示rgb
// showpicDlg.cpp : 实现文件 // #include "stdafx.h" #include "showpic.h" #include "showpicDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif   // ...
950 0
directdraw显示yuv420(YV12)
<p>height=width=widthBytes=0;<br>  m_screen.SetWindowPos(&amp;CWnd::wndBottom,0,0,720,576, SWP_NOMOVE | SWP_SHOWWINDOW);<br>  UpdateWindow();<br>  main_window_handle = m_screen.GetSafeHwnd();</
1278 0
directdraw显示yuv422(yuy2)
<p><br> #include &lt;mmsystem.h&gt;<br> void CshowpicDlg::OnBnClickedButton3()<br> {<br>  // TODO: 在此添加控件通知处理程序代码</p> <p>    height=width=widthBytes=0;<br>  m_screen.SetWindowPos(&amp;CWnd::
2447 0