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