龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > VC开发 >

Windows下的动画特技―淡入淡出

时间:2009-12-30 15:42来源:未知 作者:admin 点击:
分享到:
动画程序设计是多煤体程序设计的另一个方面,在程序设计中适当的引入动画特技,能够使程序更加生动活泼。与其它多煤体程序设计不同的是,动画并不需要特殊的多煤体硬件设备加

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

一. 淡入淡出(Dissolve)

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

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

二. 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;
}
 

精彩图集

赞助商链接