Windows下的动画特技 —淡入淡出
动画程序设计是多煤体程序设计的另
一个方面,在程序设计中适当的引入动画特
技,能够使程序更加生动活泼。与其它多煤
体程序设计不同的是,动画并不需要特殊的
多煤体硬件设备加以支持。本文将以动画特
技中的“淡入淡出”技术为例来说明如何协
同Windows和Visual C++来共同完成动画
程序设计。
一. 淡入淡出(Dissolve)
淡入淡出技术源于电影业,电影制作人
利用淡入淡出技术来完成一副图象A到另
一副图象B的转换。电影中的淡入淡出技
术可以通过制作许多中间过渡图象来实
现。
图1 图象淡入淡出过程
然而,在计算机上完成淡入淡出则是另一回
事,使用过渡图象的方法既不实际也不必
要。一种可行的办法是∶在已显示的位图A
上,不断开些小洞,在小洞内显示位图B
的象素,随着小洞逐渐增多,位图A越来
越模糊,位图B越来越清晰,最后,位图A
消失,位图B完整的显示出来,这个过程
可参见图1。
二. Windows调色板
完成淡入淡出,首先必须能够正确的显
示图象,这要求能够正确的处理颜色。
彩色显示器能够显示很多种颜色,但在
一般情况下,在给定的时刻只能显示一定数
目的颜色。在VGA和SVGA这类显示控制
器上都使用调色板来限制应用程序所能使
用的颜色的数目。调色板规定了一个颜色集
合(一般为256项),屏幕象素值对应调色板
的一个表项的索引。
在Windows系统下,系统中同时会有
多个应用程序在运行,桌面上将显示多个窗
口,而每个窗口对颜色的需求可能是不一样
的。然而,整个显示是共用一个物理调色
板,若某个窗口出于本身的需要改变了物理
调色板,则可能造成其它窗口显示不正确的
颜色。为解决上述矛盾,Windows引入了逻
辑调色板和系统调色板的概念。系统调色板
(或称硬件调色板)即物理调色板,它是整个
桌面的调色板,应用程序通过创建一个或多
个逻辑调色板的方法来使用系统调色板。当
一个窗口请求使用其逻辑调色板时,系统完
成逻辑调色板到系统调色板的映射,映射的
过程如下∶
? 系统调色板保留前10种和后10种
颜色作为静态色,用于Windows
系统颜色。
? 逻辑调色板中的项与系统调色板
中的项做完全匹配(RGB值相同的
项)。
? 对逻辑调色板中不完全匹配的
项,Windows将其设置到系统调色
板中的未用项。
? 如果系统调色板的所有项都被使
用,Windows将逻辑调色板其余的
项匹配到系统调色板中尽可能相
近的表项上(称为不完全匹配)。
Windows总是先满足活动窗口对颜色
的需求,对于剩下的窗口,Windows沿Z
次序(窗口铺放在桌面的次序)满足最近接收
到输入焦点的窗口。
VC++的MFC提供了类Cpalette和
CDC进行对调色板的有关操作。下面是一
些常用的函数∶
? Cpalette::CreatePalette()
创建调色板
? CDC::SelectPalette()
将调色板选进设备
? CDC::RealizePalette()
调色板实现
三. BitBlt()与三元光珊操作
在MFC中CDC::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 =11110000,Destination =
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;
}