裁减器
裁减器
返回上级
- 什么是“裁减器(Clipper)”对象
- 裁减清单(Clip list)
- 共享DirectDrawClipper对象
- 独立的DirectDrawClipper对象
- 用CoCreateInstance创建DirectDrawClipper对象
- 对系统鼠标使用裁减器
- 对多窗口使用Clipper
什么是“裁减器(Clipper)”对象
返回目录
裁减器,或DirectDrawClipper对象,限定你的Blit操作到一个指定的页面区域。一个裁减器对象拥有一个或多个裁减清单。一个裁减清单是一个或一系列封闭的矩形,描述了页面上的一个或一系列区域,只有在该区域内才允许Blit。这些区域是用RECT结构来描述的,按屏幕坐标。
裁减清单是一个颇有价值的工具。它们最通常的作用是阻止你的应用程序在Blit操作时,超出屏幕的边界。举例来说,想象一个子图形从屏幕的一边逐渐进入屏幕。你不会想让你的子图形是突然出现在屏幕上的;你想让它从屏幕的边上一点一点的出现。如果没有裁减器对象,你应该需要在程序中加入一个逻辑判断和运算,逐步修改Blit操作的参数,以保护那些超出屏幕边缘的页面内存,如果没有这些逻辑操作的话,你的应用程序会产生内存访问异常(memory access violations)的错误。,
下面的插图展示了这种类型的裁减。
你可以使用裁减器对象来指定目标页面的特定区域为可写的。DirectDraw在这些区域中裁减Blit操作,以保护那些指定裁减矩形以外的区域不被改写。
下面的例图展示了这种类型的裁减。
裁减清单
返回目录
DirectDraw用DirectDrawClipper对象来管理裁剪表。一个裁剪表是描述页面可见区域的一系列矩形。一个DirectDrawClipper对象可以被依附于任何一个页面。一个窗口句柄同样也可以与一个DirectDrawClipper对象相依附,在这种情况下,DirectDraw更新窗口的DirectDrawClipper对象的裁减表。
尽管在DirectDraw HAL看来,裁减表是可见的,但DirectDraw调用HAL只用于符合裁剪表所需要的矩形区域。比如,如果一个页面的右上方被裁减,并且应用程序指示DirectDraw将这个页面映射到主页面(primary surface)上,则DirectDraw将会使HAL进行两个映射,首先是页面的左上角,其次是页面的下部区域。
通过IDirectDrawClipper::SetClipList函数,你可以将整个裁减清单连接到裁减器上(如果设备支持该操作),而不是多次调用该函数,每次连接裁减清单中的一个矩形。除此之外,通过调用IDirectDrawClipper::SetHWnd函数,并且指定一个窗口的句柄,你还可以将该窗口连接到裁减器上。如果你已经让裁减器使用一个窗口句柄,那么,你将不能给该裁减器再设置另外的矩形。
覆盖页面的裁减只有在覆盖硬件可以支持,并且目标关键色没有被激活的情况下才能使用。
共享DirectDrawClipper对象
返回目录
DirectDrawClipper对象可以被多个页面所共享。例如,同一个DirectDrawClipper对象可以被设置到一个换页链的前台缓存(front buffer)和后台缓存(back buffer)上。当应用程序使用IDirectDrawSurface3::SetClipper,将一个DirectDrawClipper对象依属到一个页面,则页面将递增该DirectDrawClipper对象的引用记录(reference count)。当页面的引用记录达到0时,页面将递减DirectDrawClipper对象的引用记录。除此之外,如果调用IDirectDrawSurface3::SetClipper,并使其裁减接口指针为NULL,则DirectDrawClipper对象将从页面上分离,其引用记录也将递减1。
注意:如果在同一页面多次调用IDirectDrawSurface3::SetClipper以依属同一个DirectDrawClipper对象,则它的引用记录只会递增一次。以后的调用不会影响到该对象的引用记录。
独立的DirectDrawClipper对象
返回目录
你可以创建不直接属于任何特定DirectDraw对象的DirectDrawClipper对象。这些DirectDrawClipper对象可以被多个DirectDraw对象所共享。驱动无关(Driver-independent)的DirectDrawClipper对象是用DirectDraw的新函数DirectDrawCreateClipper创建的。应用程序可以在任何DirectDraw对象创建之前调用此函数。
因为DirectDraw对象不拥有这些DirectDrawClipper对象,所以它们不会在应用程序的DirectDraw对象被释放时自动被释放。如果应用程序没有明确的释放这些DirectDrawClipper对象,DirectDraw引擎将在应用程序结束时释放它们。
你仍然可以使用IDirectDraw2::CreateClipper函数创建DirectDrawClipper对象。这些DirectDrawClipper对象会在创建它们的DirectDraw对象被释放时,被自动释放。
用CoCreateInstance创建DirectDrawClipper对象
返回目录
DirectDrawClipper对象拥有COM所支持的全部类功能。除了使用标准的DirectDrawCreateClipper 和 IDirectDraw2::CreateClipper创建一个DirectDrawClipper对象外,你同样可以使用CoGetClassObject来获得一个类对象,然后再调用CoCreateInstance,或者直接调用CoCreateInstance来创建它。下面的例子展示了如何使用CoCreateInstance 和 IDirectDrawClipper::Initialize来创建一个DirectDrawClipper对象。
ddrval = CoCreateInstance(&CLSID_DirectDrawClipper,
NULL, CLSCTX_ALL, &IID_IDirectDrawClipper, &lpClipper);
if (!FAILED(ddrval))
ddrval = IDirectDrawClipper_Initialize(lpClipper,
lpDD, 0UL);
在CoCreateInstance调用中,第一个参数,CLSID_DirectDrawClipper,是DirectDrawClipper对象类的类标志符,IID_IDirectDrawClipper 参数指名了当前所支持的接口,lpClipper 参数指向返回的DirectDrawClipper对象。
在使用这种类机制创建DirectDrawClipper后,应用程序必须调用IDirectDrawClipper::Initialize来初始化该对象,否则该对象无法使用。dwFlags参数的值是0UL,在这种情况下,该值为0,因为现在还没有可以支持的标志符。在这个例子种,lpDD是拥有该DirectDrawClipper对象的DirectDraw对象。然而,你也可以提供NULL值,这将创建一个独立的DirectDrawClipper对象。(这相当于使用DirectDrawCreateClipper函数来创建一个DirectDrawClipper对象)
在关闭应用程序之前,用CoUninitialize函数来关闭COM。
CoUnitialize();
对系统鼠标使用裁减器
返回目录
DirectDraw应用程序通常需要为用户提供一个鼠标指针。对于全屏独占模式的应用程序来说,如果使用了换页操作,那么要实现鼠标指针的唯一选择是使用子图,通过接受由DirectInput设备或由Windows鼠标消息传来的数据控制子图的移动。然而,任何应用程序,只要没有使用换页操作,仍然是可以使用Windows系统的缺省鼠标指针的。
当你使用系统的鼠标指针时,在某些情况下,当你在Blit到主页面的某些区域时,你将沦为图形杂点的牺牲品。这些图形杂点象鼠标指针那样出现在屏幕上,就好象是系统留下的。
通过阻止鼠标指针图象在Blit操作过程中“挡道”, 一个DirectDrawClipper对象可以防止这样的杂点出现。这也是一个相对而言较简单的解决办法。步骤是这样的:首先,调用IDirectDraw2::CreateClipper创建一个DirectDrawClipper对象;然后,通过调用IDirectDrawClipper::SetHWnd函数将你的应用程序的窗口句柄连接到该裁减器对象上。一旦一个裁减器对象被连接到一个窗口后,任何后续的对主页面进行的Blit操作(通过调用IDirectDrawSurface3::Blt函数)将不会出现任何鼠标杂点。
注意:IDirectDrawSurface3::BltFast函数,以及它的IDirectDrawSurface和IdirectDrawSurface2接口的版本,将不能对隶属于页面的裁减器进行操作。
对多窗口使用Clipper
返回目录
你可以使用一个单独的DirectDrawClipper对象,对由单独的应用程序创建的多个窗口进行Blit操作。
这个方法是这样的。首先,创建一个单独的DirectDraw对象以及一个主页面。然后,创建一个DirectDrawClipper对象,并且将它连接到你的主页面上(通过调用IDirectDrawSurface3::SetClipper函数)。要使Blit操作仅限于窗口的客户区,在Blit到主页面之前,将该窗口的句柄设置给该裁减器(通过调用IDirectDrawClipper::SetHWnd函数)。只要你需要Blit到另一个窗口的客户区,再次调用IDirectDrawClipper::SetHWnd函数,将另一个窗口的句柄设置给裁减器。
创建多个DirectDraw对象,并且让它们Blit到相互的主页面是不推荐的做法。上面所介绍的技术提供了一个有效和可靠的Blit到多客户区的方法,针对的是单独的DirectDraw对象。