Windows下的动画特技淡入淡出


动画程序设计是多煤体程序设计的另
一个方面,在程序设计中适当的引入动画特
技,能够使程序更加生动活泼。与其它多煤
体程序设计不同的是,动画并不需要特殊的
多煤体硬件设备加以支持。本文将以动画特
技中的淡入淡出技术为例来说明如何协
WindowsVisual C++来共同完成动画
程序设计。

一. 淡入淡出(Dissolve)

淡入淡出技术源于电影业,电影制作人
利用淡入淡出技术来完成一副图象A到另
一副图象B的转换。电影中的淡入淡出技
术可以通过制作许多中间过渡图象来实
现。





1 图象淡入淡出过程

然而,在计算机上完成淡入淡出则是另一回
事,使用过渡图象的方法既不实际也不必
要。一种可行的办法是在已显示的位图A
上,不断开些小洞,在小洞内显示位图B
的象素,随着小洞逐渐增多,位图A越来
越模糊,位图B越来越清晰,最后,位图A
消失,位图B完整的显示出来,这个过程
可参见图1

二. Windows调色板

完成淡入淡出,首先必须能够正确的显
示图象,这要求能够正确的处理颜色。
彩色显示器能够显示很多种颜色,但在
一般情况下,在给定的时刻只能显示一定数
目的颜色。在VGASVGA这类显示控制
器上都使用调色板来限制应用程序所能使
用的颜色的数目。调色板规定了一个颜色集
(一般为256),屏幕象素值对应调色板
的一个表项的索引。
Windows系统下,系统中同时会有
多个应用程序在运行,桌面上将显示多个窗
口,而每个窗口对颜色的需求可能是不一样
的。然而,整个显示是共用一个物理调色
板,若某个窗口出于本身的需要改变了物理
调色板,则可能造成其它窗口显示不正确的
颜色。为解决上述矛盾,Windows引入了逻
辑调色板和系统调色板的概念。系统调色板
(
或称硬件调色板)即物理调色板,它是整个
桌面的调色板,应用程序通过创建一个或多
个逻辑调色板的方法来使用系统调色板。当
一个窗口请求使用其逻辑调色板时,系统完
成逻辑调色板到系统调色板的映射,映射的
过程如下
?
系统调色板保留前10种和后10
颜色作为静态色,用于Windows
系统颜色。
?
逻辑调色板中的项与系统调色板
中的项做完全匹配(RGB值相同的
)
?
对逻辑调色板中不完全匹配的
项,Windows将其设置到系统调色
板中的未用项。
?
如果系统调色板的所有项都被使
用,Windows将逻辑调色板其余的
项匹配到系统调色板中尽可能相
近的表项上(称为不完全匹配)
Windows
总是先满足活动窗口对颜色
的需求,对于剩下的窗口,Windows沿Z
次序(窗口铺放在桌面的次序)满足最近接收
到输入焦点的窗口。
VC++
MFC提供了类Cpalette
CDC
进行对调色板的有关操作。下面是一
些常用的函数
? Cpalette::CreatePalette()
创建调色板
? CDC::SelectPalette()
将调色板选进设备
? CDC::RealizePalette()
调色板实现

三. BitBlt()与三元光珊操作

MFCCDC::BitBlt()在两个设备对
象的位图之间进行逻辑操作。其原型为
BOOL BitBlt(int x , int y , int nWidth , int
nHeight , CDC* pSrcDC , int xSrc , int ySrc ,
DWORD dwRop) ;
其中,xSrc,ySrc是源设备上要移动的位
图的起始点,x,y,nWidth,hHeight参数表示
目的设备矩形起始点坐标,宽和高,nWidth
nHeight也用于源设备。dwRop是三元光
珊操作代码。BitBlt在进行位图复制时要对
三个对象进行逻辑组合(因此称为三元光珊
操作)目的设备中选定的画刷,源设备中
所要复制的矩形中的位图和目的设备中矩
形的位图。画刷是一个8*8的位图,可以使
CDC::CreatePatternBrush()创建。
淡入淡出实际上就是通过BitBlt()函数
进行将位图A放入目的设备,将位图B
放入源设备,利用画刷在位图A上打洞并
以位图B的象素填入,不断改变画刷使洞
越来越多进行BitBlt()操作,最后完成整个
过程。完成上述过程需要选择一个合适的
ROP
操作码,下面说明如何计算这个操作

上述过程实际上可以分成两步进行
1.
利用画刷在目的位图上打洞
2.
将位图B的象素填入洞中。
完成第一步可以采用AND操作,即
Pattern & Destination
。通过这个操作,画刷
中的黑点对应的象素值为0 (0&
Destination=0)
,滤去了Destination的象素;
而画刷中的白点对应象素处仍保持
Destination
的象素值(1&Destination
=Destination)
。同样道理,第二步可以采用
操作(~Pattern) & Source将画刷黑点对应象
素置为Source的象素值,画刷白点对应象
素值为0。最后,两各操作进行OR即可完
成指定操作。因此,最后的ROP操作为
(Pattern & Destination) | ((~Pattern) &
Source))
Pattern =11110000Destination =
10101010
Source=11001100可以计算出
ROP
码为10101100=0xAC,查ROP操作码
表可得最后的ROP码为0x00AC0744

四. 淡入淡出例程

下面的例程说明了淡入淡出特技的实
现过程。创建该例程的步骤如下
1.
利用AppWizard创建一个基于对话框
的工程。
2.
添加产生画刷的过程
Cbrush* Cdissolve::CreateDissolveBrush(int Step)
{
//
创建画刷所需数据
static int data[65] = {
1, 5,33,37,19,23,51,55,17,21,49,53, 3, 7,35,39,
10,14,42,46,28,32,60,64,26,30,58,62,12,16,44,48,
8, 4,40,36,22,18,54,50,24,20,56,52, 6, 2,38,34,
15,11,47,43,29,25,61,57,31,27,63,59,13, 9,45,41
};
if (Step<0||Step>m_maxstep-1) return NULL;
Cbrush* pBrush = new Cbrush;
//
最后一步使用黑画刷
if (Step==m_maxstep-1)
{
pBrush->CreateSolidBrush(RGB(0,0,0));
return pBrush;
}
//
计算画刷数据
BYTE pixels[16];
for (int I=0;I<8;I++) pixels[I*2] = 0xFF;
for (I=1;I<=(Step*(64/m_maxstep));I++)
{
int row = (data[I]-1)/8;
int col = (data[I]-1)%8;
pixels[row*2]=pixels[row*2 ]&(~(BYTE)pow(2
,col));
}

//
创建画刷
Cbitmap bitmap;
if (!bitmap.CreateBitmap(8,8,1,1,pixels))
{
m_LastError = ERR_BMP_CREATE;
return NULL;
}
if (!pBrush->CreatePatternBrush(&bitmap))
{
m_LastError = ERR_BRUSH_CREATE;
return NULL;
}

return pBrush;
}