分享
 
 
 

DircetDraw c/c++ 使用指导(一)

王朝c/c++·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

DircetDraw c/c++ 使用指导

310cdt 译

边看边译,译完就拿了上来,见笑了

这是一系列的DirectDraw的指南,教你一步步的去构建一个简单的DirectDraw应用.这个指南用到了sdk包提供的很多DirectDraw的例子.这些例子展示了怎样设置DirectDraw,怎样用DirectDraw方法实现一般任务:

注意:这些指南中的例子是用c++写的.如果你使用的是c编译器,请进行适当的改变,以能进行成功的编译.你需要把vtable和this指针添加到接口方法中.

1.DirectDraw基础用法

要使用DirectDraw,你必须先创建一个代表计算机显示接口的DirectDraw实例.然后,你就可以通过接口的方法来操纵这个对象.你可能会需要创建一个或更多的DirectDraw平面对象(DirectDraw surface object)的实例

来在图形设备上显示你的应用程序.

为了演示这个,例子DDEx1 sample((SDK root)\Samples\Multimedia\DDraw\Src\Ddex1)演示了以下几步:

step 1:创建一个DirectDraw对象

想创建一个DirectDraw对象的实例,你的应用程序必须在InitApp函数中使用DirectDrawCreateEx函数,就像例程ddex1中一样.DirectDrawCreateEx函数包括4个参数.第一个是:显示设备全局唯一标识(GUID).GUID大部分情况下是设为NULL,选择系统默认的显示设备.第二个参数是:包含的是标示DirectDraw对象是否建立的指针的地址.第三个参数是IDirectDraw7接口的参考标示.必须设为IID_IDirectDraw7.第四个参数是设置为NULL的,是为了将来的扩展做准备的.

以下的例子展示了怎样创建DirectDraw对象,并判断创建是否成功.

hRet = DirectDrawCreateEx(NULL, (VOID**)&g_pDD, IID_IDirectDraw7, NULL);

if(hRet == DD_OK)

{

// g_pDD is a valid DirectDraw object.

}

else

{

// The DirectDraw object could not be created.

}

step2:决定程序的行为

在你改变显示方法前,你必须至少在IDirectDraw7::SetCooperativeLevel函数中指定dwFlags参数(DDSCL_EXCLUSIVE 和 DDSCL_FULLSCREEN).这样,你的应用程序就得到了显示设备的全部控制权,其他的程序不能共享.DDSCL_FULLSCREEN让你的应用程序在全屏幕模式下运行.你的程序覆盖了桌面,并且只有你的程序能在屏幕上输出.但是,桌面仍然是有效的.(按ALT+TAB切换到桌面)

下面的例子演示了SetCooperativeLevel函数的用法.

HRESULT hRet;

LPDIRECTDRAW7 g_pDD; // already created by DirectDrawCreateEx

hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);

if (hRet != DD_OK)

{

// Exclusive mode was successful.

}

else

{

// Exclusive mode was not successful.

// The application can still run, however.

}

如果 SetCooperativeLevel不返回DD_OK,你可以指定为DDSCL_NORMAL继续运行你的程序.但是,你的程序不再是独占模式,而且,可能会无法完成你的一部分要求.在这种情况下,你最好显示一个对话框让用户决定是否要继续.

如果你设置的是全屏幕独占合作级别,你必须把程序的窗口句柄传递给SetCooperativeLevel,这样可以让Windows有能力决定你的程序是否异常终止.

step3 :改变显示模式

接下来,你可以用IDirectDraw7::SetDisplayMode函数来改变显示模式.下面的例子将演示怎样把显示模式设置为640 × 480 × 8 bits per pixel (bpp).

HRESULT hRet;

LPDIRECTDRAW7 g_pDD; // already created by DirectDrawCreateEx

hRet = g_pDD->SetDisplayMode(640, 480, 8, 0, 0);

if (hRet != DD_OK)

{

// The display mode changed successfully.

}

else

{

// The display mode cannot be changed.

// The mode is either not supported or

// another application has exclusive mode.

}

当你设置显示模式的时候,你应该确定用户的硬件是否支持这样的模式.你可以设置一个能被大部分显示适配器支持的标准的模式.例如:你的程序可以以640 × 480 × 8作为备选模式,设计成为可以在所有系统上运行.

注意:IDirectDraw7::SetDisplayMode返回一个DDERR INVALIDMODE错误值,如果显示适配器无法切换到想要的模式时.你可以在试图改变显示模式前,用IDirectDraw7::EnumDisplayModes函数看一下用户显示适配器的能力.

step4:创建交换页(flipping surface)

设置完显示模式以后,你应该创建一个平面.例程:DDEx1用IDirectDraw7::SetCooperativeLevel 设置为独占模式.所以,你可以创建交换页(flipping surfaces).如果你设置的是DDSCL_NORMAL模式,你可以创建一个可以块移动(blit)的平面.创建交换页(flipping surfaces)需要以下步骤:

(4.1)定义需求的平面:

第一步是以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错误)

(4.2)创建平面

在填充完DDSURFACEDESC2结构后,你就可以用他和g_pDD指针(DirectDrawCreateEx函数创建的DirectDraw对象的指针)调用IDirectDraw7::CreateSurface方法,就像下面 :

hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);

if (hRet != DD_OK)

{

// g_pDDSPrimary points to the new surface.

}

else

{

// The surface was not created.

return FALSE;

}

g_pDDSPrimary参数将指向由CreateSurface函数返回的主平面(primary surface)的地址,如果调用成功的话.

指向主平面(primary surface)的指针有效后,就可以调用IDirectDrawSurface7::GetAttachedSurface方法去得到一个指向缓冲的指针.如下:

ZeroMemory(&ddscaps, sizeof(ddscaps));

ddscaps.dwCaps = DDSCAPS_BACKBUFFER;

hRet = g_pDDSPrimary->GetAttachedSurface(&ddscaps, &g_pDDSBack);

if (hRet != DD_OK)

{

// g_pDDSBack points to the back buffer.

}

else

{

return FALSE;

}

如果IDirectDrawSurface7::GetAttachedSurface调用成功,g_pDDSBack参数将指向缓存区.

step5:在平面上输出

在主平面(primary surface)和后台缓冲(back buffer)创建完成后,例子DDEx1用windows标准GDI函数输出了一些文本在缓冲上.如下:

if (g_pDDSBack->GetDC(&hdc) == DD_OK)

{

SetBkColor(hdc, RGB(0, 0, 255));

SetTextColor(hdc, RGB(255, 255, 0));

if (phase)

{

GetClientRect(hWnd, &rc);

GetTextExtentPoint(hdc, szMsg, lstrlen(szMsg), &size);

TextOut(hdc, (rc.right - size.cx) / 2, (rc.bottom - size.cy) / 2,

szMsg, sizeof(szMsg) - 1);

TextOut(hdc, 0, 0, szFrontMsg, lstrlen(szFrontMsg));

phase = 0;

}

else

{

TextOut(hdc, 0, 0, szBackMsg, lstrlen(szBackMsg));

phase = 1;

}

g_pDDSBack->ReleaseDC(hdc);

}

这个例子使用the IDirectDrawSurface7::GetDC方法获得设备上下文的句柄,并且,为了准备写入,将缓冲上锁.如果你不准备用需要设备上下文句柄的windows函数,你可以使用IDirectDrawSurface7::Lock IDirectDrawSurface7::Unlock方法加解锁.

接下来,phase变量决定了应该输出到主缓存消息(primary buffer message)还是后台缓存消息(back buffer message).如果phase=1,输出

主缓存消息,且设phase=0.如果phase=0,输出后台缓存消息,且设phase=1.

当消息输出到缓存区后,用IDirectDrawSurface7::ReleaseDC 方法将缓存区解锁.

对创建平面的内存上锁,是保证你的程序和系统不能同时对此内存进行存取.这防止你写入"平面"内存事发生错误.另外,不对"平面"内存解锁,你的程序将无法翻转平面.

平面被加锁之后,例子中用了标准windowsGDI函数:SetBkColor设置背景色,SetTextColor设置在背景上显示的字的颜色,用TextOut在"表面"上输出文字和背景色.

当文字被输出到缓存之后,例子应用IDirectDrawSurface7::ReleaseDC方法解锁"表面"并且释放句柄.不论在什么时候你的程序完成了对缓存的写入,一定要调用IDirectDrawSurface7::ReleaseDC 或IDirectDrawSurface7::Unlock之一,具体用哪个,由你的程序而定.不解锁,你的程序将不能翻转平面.

注意:用IDirectDrawSurface7::Unlock对"平面"解锁后,指向"平面"的指针将会无效.你必须再用IDirectDrawSurface7::lock去获得一个有效的指针.

step:6 翻转平面

在DDEx1中,WM_TIMER消息引发从缓存到主平面的翻转.当"平面"内存解锁后,你就可以用IDirectDrawSurface7::Flip方法实现从缓存到主平面的翻转.如下:

case WM_TIMER:

// Update and flip surfaces

if (g_bActive && TIMER_ID == wParam)

{

UpdateFrame(hWnd);

while (TRUE)

{

hRet = g_pDDSPrimary->Flip(NULL, 0);

if (hRet == DD_OK)

break;

if (hRet == DDERR_SURFACELOST)

{

hRet = g_pDDSPrimary->Restore();

if (hRet != DD_OK)

break;

}

if (hRet != DDERR_WASSTILLDRAWING)

break;

}

}

break;

在例子中,g_pDDSPrimary参数指示主平面和与他连接的缓存.当IDirectDrawSurface7::Flip被调用,前后平面将会交换(只是交换指针,没有实际的数据交换).如果翻转成功,返回DD_OK,跳出循环.

如果翻转返回的是DDERR_SURFACELOST值,就试图用IDirectDrawSurface7::Restore 方法保存平面.如果保存成功,程序循环到调用IDirectDrawSurface7::Flip,再试一次.如果保存不成功,程序跳出循环,返回一个错误.

注意:当你调用IDirectDrawSurface7::Flip 时,翻转动作并不能马上完成.如果,前一个翻转动作还没有完成,IDirectDrawSurface7::Flip 会返回DDERR_WASSTILLDRAWING.在这个例子中,IDirectDrawSurface7::Flip会一直调用直到返回DD_OK.

step7:释放DirectDraw对象

当你按下F12键时,例子DDEx1将在退出程序前处理WM_DESTROY消息.这个消息将调用ReleaseAllObjects函数,这个函数包括了多个Release调用.像下面一样:

static void

ReleaseAllObjects(void)

{

if (g_pDD != NULL)

{

if (g_pDDSPrimary != NULL)

{

g_pDDSPrimary->Release();

g_pDDSPrimary = NULL;

}

g_pDD->Release();

g_pDD = NULL;

}

}

这个程序检测DirectDraw对象的指针g_pDD和DirectDraw平面对象的指针g_pDDSPrimary是否为NULL.然后,调用IDirectDrawSurface7::Release方法令DirectDraw平面对象的reference count(可以认为是创建的对象的数目)数减1,这使得reference count减为0,DirectDraw平面对象就释放了.然后,还需将他的指针值设为NULL.接下来,程序调用IDirectDraw7::Release,同样是令DirectDraw的reference count减1,然后然后....全销毁.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有