www.gusucode.com > 包含近30种图像特效的VC++小程序源码程序 > 包含近30种图像特效的VC++小程序源码程序/code/Animation.cpp

    //Download by http://www.NewXing.com
/////////////////////////////////////////////////////////////////////////
//类名:CAnimationEngine
//功能:屏保的各种动画文字及位图显示效果
//修改:徐景周(jingzhou_xu@163.net)
//组织:未来工作室(Future Studio)
//日期:2002.1.8
////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Animation.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// CAnimationItem

CAnimationItem::CAnimationItem()
{
	SetDefaults();
	m_pAE = NULL;
}

CAnimationItem::CAnimationItem( CAnimationEngine* pAE )
{
	SetDefaults();
	m_pAE = pAE;
}

CAnimationItem::~CAnimationItem()
{
}

CAnimationItem& CAnimationItem::SetDefaults()
{
	m_nFrames = 20;
	m_nEffects = 0;
	m_pFont = NULL;
	m_pBitmap = NULL;
	int nFirstPic = -1;
	int nLastPic = -1;
	SetTextColor( RGB(191,191,191) );
	SetPoint( CPoint(0,0) );
	m_bDrawnYet = FALSE;
	m_bWait = FALSE;
	m_posKickOff = NULL;
	m_posNext = NULL;
	return *this;
}

CAnimationItem& CAnimationItem::SetFont( CString csFont )
{
	m_pFont = m_pAE->GetFont( csFont );
	return *this;
}

CAnimationItem& CAnimationItem::SetBitmap( UINT nBitmapID, int nFirst, int nLast )
{
	m_pBitmap = m_pAE->GetBmp( nBitmapID );
	m_nFirstPic = nFirst;
	m_nLastPic = nLast;
	return *this;
}

CAnimationItem& CAnimationItem::SetTextColor( COLORREF rgb )
{
	m_rgbTextColor = rgb;
	m_rgbTextColorCurrent = rgb;
	return *this;
}

CAnimationItem& CAnimationItem::SetText( CString csText )
{
	m_csText = csText;
	return *this;
}

CAnimationItem& CAnimationItem::SetStart( CPoint pt )
{
	m_ptStart = pt;
	m_pt = m_ptStart;
	m_dX = pt.x;
	m_dY = pt.y;
	return *this;
}

CAnimationItem& CAnimationItem::SetFinish( CPoint pt )
{
	m_ptFinish = pt;
	return *this;
}

CAnimationItem& CAnimationItem::SetPoint( CPoint pt )
{
	SetStart( pt );
	return SetFinish( pt );
}

CAnimationItem& CAnimationItem::SetFrames( int nFrames )
{
	m_nFrames = nFrames;
	return *this;
}

CAnimationItem& CAnimationItem::GoAfter( POSITION pos )
{
	if ( ! pos )
		return *this;
	CAnimationItem* pItem = &m_pAE->m_listItems.GetAt( pos );
	if ( pItem->m_posKickOff )
		m_posNext = pItem->m_posKickOff;
	pItem->m_posKickOff = m_pos;
	m_bWait = TRUE;
	return *this;
}

CAnimationItem& CAnimationItem::GoWith( POSITION pos )
{
	if ( ! pos )
		return *this;
	CAnimationItem* pItem = &m_pAE->m_listItems.GetAt( pos );
	m_posNext = pItem->m_posNext;
	m_bWait = pItem->m_bWait;
	pItem->m_posNext = m_pos;
	return *this;
}

//////////////////////////////////////////////////////////////////////
// CAnimationEngine

CAnimationEngine::CAnimationEngine()
{
	m_rect.SetRectEmpty();
	m_rgbBackground = RGB(0,0,0);
	m_brushBackground.CreateStockObject(BLACK_BRUSH);
	m_pDefaultFont = GetFont( "15,MS Sans Serif" );
	srand( (unsigned)time( NULL ) );
}

CAnimationEngine::~CAnimationEngine()
{
	DestroyGDIs();
}

CAnimationItem& CAnimationEngine::CreateItem( CString csText )
{
	CAnimationItem item( this );
	item.m_csText = csText;
	POSITION pos = m_listItems.AddTail( item );
	CAnimationItem& itemRef = m_listItems.GetAt( pos );
	itemRef.m_pos = pos;
	return itemRef;
}

CAnimationItem& CAnimationEngine::CreateItemAfter( POSITION pos )
{
	CAnimationItem& itemFrom = m_listItems.GetAt( pos );
	CAnimationItem& itemRef = CreateItem( itemFrom.m_csText );
	itemRef.m_csText = itemFrom.m_csText;
	itemRef.SetPoint( itemFrom.m_ptFinish );
	itemRef.SetTextColor( itemFrom.m_rgbTextColor );
	itemRef.m_pFont = itemFrom.m_pFont;
	itemRef.m_nEffects |= (itemFrom.m_nEffects &
		(CAnimationItem::AF_AlignCenter|CAnimationItem::AF_AlignRight));
	itemRef.GoAfter( pos );
	itemRef.m_pBitmap = itemFrom.m_pBitmap;
	itemRef.m_nFirstPic = itemFrom.m_nFirstPic;
	itemRef.m_nLastPic = itemFrom.m_nLastPic;
	return itemRef;
}

int CAnimationEngine::RunFrame( CDC& dc )
{
	// Setup DC
	CFont* pOldFont = dc.SelectObject( m_pDefaultFont );
	dc.SetBkColor( RGB(0,0,0) );
	dc.SetBkMode( TRANSPARENT );
	CRect rect;

	// Loop through items
	int nItems = 0, nItemsAlive = 0;
	POSITION pos = m_listItems.GetHeadPosition();
	while ( pos )
	{
		POSITION posCurrent = pos;
		CAnimationItem& item = m_listItems.GetNext( pos );

		++nItems;
		if ( item.m_bWait )
			continue;
		++nItemsAlive;

		// Font
		if ( item.m_pFont )
			dc.SelectObject( item.m_pFont );
		else
			dc.SelectObject( m_pDefaultFont );

		// Alignment
		DWORD nDrawFlags = DT_WORDBREAK;
		if ( item.m_nEffects & item.AF_AlignRight )
			nDrawFlags |= DT_RIGHT;
		else if ( item.m_nEffects & item.AF_AlignCenter )
			nDrawFlags |= DT_CENTER;

		// Set flag if erase is necessary (always erase on last step)
		BOOL bErase = ( ! item.m_nFrames );

		// Calculate new position
		CPoint ptNew = item.m_pt;
		if ( item.m_bDrawnYet && item.m_ptStart != item.m_ptFinish )
		{
			if ( ! item.m_nFrames )
				ptNew = item.m_ptFinish;
			else
			{
				item.m_dX += ( ((double)item.m_ptFinish.x) - item.m_dX ) / ((double)item.m_nFrames);
				item.m_dY += ( ((double)item.m_ptFinish.y) - item.m_dY ) / ((double)item.m_nFrames);
				ptNew = CPoint( (int)item.m_dX, (int)item.m_dY );
			}
			if ( item.m_pt != ptNew )
				bErase = TRUE;
		}

		// Calculate fade
		BOOL bFade = item.m_nEffects & (item.AF_FadeIn|item.AF_FadeOut);
		if ( bFade )
		{
			BOOL bIn = item.m_nEffects & item.AF_FadeIn;
			if ( ! item.m_nFrames )
				item.m_rgbTextColorCurrent = bIn?item.m_rgbTextColor:RGB(0,0,0);
			else
			{
				int nMask = 0xff;
				for ( int nC = 0; nC < 3; ++nC )
				{
					int nColor = (item.m_rgbTextColor & nMask) >> (8*nC);
					int nCurColor = (item.m_rgbTextColorCurrent & nMask) >> (8*nC);
					if ( bIn )
						nCurColor += ( (nColor-nCurColor) / item.m_nFrames );
					else
						nCurColor -= ( nCurColor / item.m_nFrames );
					item.m_rgbTextColorCurrent = (item.m_rgbTextColorCurrent&(~nMask)) | (nCurColor << (8*nC));
					nMask = nMask << 8;
				}
			}
		}

		// Remove if drawn previously
		if ( item.m_pBitmap )
			DrawBitmapItem( dc, item, ptNew, item.m_nFrames != 0 );
		else if ( item.m_bDrawnYet && bErase )
			DrawTextItem( dc, item, nDrawFlags, FALSE );
		item.m_bDrawnYet = FALSE;

		// See if any more frames remain for this item
		if ( ! item.m_nFrames )
		{
			POSITION posKickOff = item.m_posKickOff;
			while ( posKickOff )
			{
				CAnimationItem* pNext = &m_listItems.GetAt( posKickOff );
				pNext->m_bWait = FALSE;
				posKickOff = pNext->m_posNext;
				pNext->m_posNext = NULL;
			}
			m_listItems.RemoveAt( posCurrent );
			continue;
		}
		--item.m_nFrames;

		// Draw at new position
		item.m_pt = ptNew;
		if ( ! item.m_pBitmap )
			DrawTextItem( dc, item, nDrawFlags, TRUE );
		item.m_bDrawnYet = TRUE;
	}

	if ( nItems && ! nItemsAlive )
		ASSERT( 0 );

	dc.SelectObject( pOldFont );
	return nItems;
}

// ---------------------------------------------------------
//	名称: DrawBitmapItem
//	功能: 绘制动画位图
//	参数: dc -- 相关DC,item --动画条项, ptNew -- 新位置
//		  bShow -- 是否显示
//	返回: 无
//	修改: 徐景周,2002.1.8
// ---------------------------------------------------------
void CAnimationEngine::DrawBitmapItem( CDC& dc, CAnimationItem& item, CPoint ptNew, BOOL bShow )
{
	CPoint pt = item.m_pt;
	CRect rectBmp( 0, 0, item.m_pBitmap->GetWidth(), item.m_pBitmap->GetHeight() );
	if ( item.m_nFirstPic != -1 )
	{
		// 计算总帧位图中每一单帧小位图大小(单行总帧位图,其中每单帧位图长、宽需相等)
		int nWidth = rectBmp.Height();
		rectBmp.right = nWidth;
		rectBmp.OffsetRect( item.m_nFirstPic*nWidth, 0 );
	}
	CRect rect( 0,0,rectBmp.Width(),rectBmp.Height() );
	rect.OffsetRect( pt );
	if ( item.m_nEffects & item.AF_AlignCenter )
		rect.OffsetRect( - rectBmp.Width()/2, 0 );
	if ( ! bShow )
	{
//		dc.FillRect( &rect, &m_brushBackground );			// 黑色背景添充,暂时去掉,jingzhou xu
		return;
	}

	if ( pt != ptNew )
	{
		// Determine rects that need to be cleared
		CRect rectLeftOrRight( rect ), rectTopOrBottom( rect );
		int nXDiff = ptNew.x - pt.x;
		int nYDiff = ptNew.y - pt.y;
		if ( nXDiff >= 0 ) // moving right
			rectLeftOrRight.right = rectTopOrBottom.left = rectLeftOrRight.left + nXDiff;
		else // moving left
			rectLeftOrRight.left = rectTopOrBottom.right = rectLeftOrRight.left + nXDiff;
		if ( nYDiff >= 0 ) // moving down
			rectTopOrBottom.bottom = rectTopOrBottom.top + nYDiff;
		else // moving up
			rectTopOrBottom.top = rectTopOrBottom.top + nYDiff;
//		dc.FillRect( &rectLeftOrRight, &m_brushBackground ); // 黑色背景添充,暂时去掉,jingzhou xu
//		dc.FillRect( &rectTopOrBottom, &m_brushBackground ); // 黑色背景添充,暂时去掉,jingzhou xu
	}

	rect.SetRect( 0,0,rectBmp.Width(),rectBmp.Height() );
	rect.OffsetRect( ptNew );
	if ( item.m_nEffects & item.AF_AlignCenter )
		rect.OffsetRect( - rectBmp.Width()/2, 0 );
	
//	item.m_pBitmap->DrawDIB( &dc, rect, rectBmp );
	// 显示透明位图,jignzhou xu
	item.m_pBitmap->DrawTransparentBitmap( &dc, rect.left,rect.top);
}

void CAnimationEngine::DrawTextItem( CDC& dc, CAnimationItem& item, int nDrawFlags, BOOL bShow )
{
	CRect rect;
	CPoint pt = item.m_pt;

	if ( bShow )
		dc.SetTextColor( item.m_rgbTextColorCurrent );
	else
		dc.SetTextColor( m_rgbBackground );

	CSize size = dc.GetTextExtent( item.m_csText );
	int nBottom = pt.y + size.cy * 2 + 1;
	if ( item.m_nEffects & item.AF_AlignCenter )
		rect.SetRect( pt.x-size.cx/2, pt.y, pt.x+size.cx/2+2, nBottom );
	else if ( item.m_nEffects & item.AF_AlignRight )
		rect.SetRect( pt.x-size.cx-1, pt.y, pt.x, nBottom );
	else
		rect.SetRect( pt.x, pt.y, pt.x+size.cx+1, nBottom );
	dc.DrawText( item.m_csText, &rect, nDrawFlags );
}

CDIBitmap* CAnimationEngine::GetBmp( UINT nBitmapID )
{
	CDIBitmap* pBmp = NULL;
	if ( ! m_mapBmps.Lookup( nBitmapID, pBmp ) )
	{
		pBmp = new CDIBitmap;
		if ( ! pBmp->LoadResource(nBitmapID) )
		{
			delete pBmp;
			return NULL;
		}

		// Create bitmap and add it to the pool
		m_mapBmps.SetAt( nBitmapID, pBmp );
	}
	return pBmp;
}

CFont* CAnimationEngine::GetFont( CString csFont )
{
	CFont* pFont;
	if ( ! m_mapFonts.Lookup( csFont, pFont ) )
	{
		// Create font and add it to the pool
		LOGFONT logfont;
		logfont.lfHeight = -12;
		logfont.lfWidth = 0;
		logfont.lfEscapement = 0;
		logfont.lfOrientation = 0;
		logfont.lfWeight = FW_NORMAL;
		logfont.lfItalic = 0;
		logfont.lfUnderline = 0;
		logfont.lfStrikeOut = 0;
		logfont.lfCharSet = ANSI_CHARSET;
		logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
		logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
		logfont.lfQuality = NONANTIALIASED_QUALITY;
		logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;
		strcpy(logfont.lfFaceName, "Arial");

		// Break out font string into comma-delimited font attributes
		CString csAttrib;
		int nComma = 0, nStart = 0;
		while ( (nComma = csFont.Find(",",nStart)) != -1 )
		{
			csAttrib = csFont.Mid( nStart, nComma - nStart );
			if ( csAttrib.GetLength() )
			{
				switch ( csAttrib[0] )
				{
				case 'B': // Bold
					if ( csAttrib.GetLength() > 1 )
						logfont.lfWeight = atoi(csAttrib.Mid(1));
					else
						logfont.lfWeight = FW_BOLD;
					break;
				case 'I': // Italic
					logfont.lfItalic = TRUE;
					break;
				case 'U': // Underline
					logfont.lfUnderline = TRUE;
					break;
				case 'S': // StrikeOut
					logfont.lfStrikeOut = TRUE;
					break;
				case 'C': // CS is CharSet
					if ( csAttrib.GetLength() > 2 )
						logfont.lfCharSet = atoi(csAttrib.Mid(2));
					break;
				default:
					if ( isdigit(csAttrib[0]) || csAttrib[0] == '-' )
						logfont.lfHeight = - atoi( csAttrib );
					break;
				}
			}
			nStart = nComma + 1;
		}
		if ( csFont.GetLength() > nStart )
		{
			strncpy(logfont.lfFaceName, csFont.Mid(nStart), LF_FACESIZE);
			logfont.lfFaceName[LF_FACESIZE-1] = '\0';
		}
		pFont = new CFont;
		pFont->CreateFontIndirect( &logfont );
		m_mapFonts.SetAt( csFont, pFont );
	}
	return pFont;
}

int CAnimationEngine::Rand( int n )
{
	int nRand = rand() * n / RAND_MAX;
	return max(0,min(nRand,n-1)); // enforce bounds
}

CPoint CAnimationEngine::RandPt( int nMargin, int nMin )
{
	int nHorizMargin = max( 0, min(m_rect.Width()/2-nMin,nMargin) );
	int nX = Rand(m_rect.Width()-nHorizMargin*2) + m_rect.left + nHorizMargin;
	int nVertMargin = max( 0, min(m_rect.Height()/2-nMin,nMargin) );
	int nY = Rand(m_rect.Height()-nVertMargin*2) + m_rect.left + nVertMargin;
	return CPoint( nX, nY );
}

void CAnimationEngine::DestroyGDIs()
{
	POSITION pos = m_mapFonts.GetStartPosition();
	while ( pos )
	{
		CString csKey;
		CFont* pFont;
		m_mapFonts.GetNextAssoc( pos, csKey, pFont );
		pFont->DeleteObject();
		delete pFont;
	}
	m_mapFonts.RemoveAll();

	pos = m_mapBmps.GetStartPosition();
	while ( pos )
	{
		UINT nID;
		CDIBitmap* pBmp;
		m_mapBmps.GetNextAssoc( pos, nID, pBmp );
		delete pBmp;
	}
	m_mapBmps.RemoveAll();

	m_brushBackground.DeleteObject();
}

void CAnimationEngine::SetScreen( CRect rect )
{
	m_rect = rect;
}