📄 ddcompo.cpp
字号:
return rcDest;
}
// 应用程序在显示鼠标光标时应该使用此函数
// draw cursor to front surface
// bForce : TRUE for force draw the cursor,
// usually used after changing the state or frame of a cursor
// bForce : TRUE for force drawing
// return value : TRUE for has drew
BOOL CDDCursor::Draw( BOOL bForce/*=FALSE*/ )
{
//if( !m_bCreatedC ) return FALSE;
Assert( m_bCreatedC == TRUE );
if( !m_bShow ) return FALSE;
POINT ptPosOld;
RECT rcDest1, rcDest2;
RECT rcSrcFile;
ptPosOld.x = m_ptPos.x;
ptPosOld.y = m_ptPos.y;
// get old destination rectangle
rcDest1 = GetRect();
// get current cursor position
GetCursorPos( &m_ptPos );
// test if needn't draw
if( m_ptPos.x == ptPosOld.x && m_ptPos.y == ptPosOld.y && !bForce )
return FALSE; // needn't
// get current destination rectangle
rcDest2 = GetRect();
// get source rectangle of the bitmap file
rcSrcFile.left = m_nFrame*m_szSize.cx;
rcSrcFile.top = m_nState*m_szSize.cy;
rcSrcFile.right = rcSrcFile.left + m_szSize.cx;
rcSrcFile.bottom = rcSrcFile.top + m_szSize.cy;
// calculate if the two rectangles cross
POINT ptDest; // destination position
RECT rcSrc; // source rectangle
// if they cross
if( IntersectRect( &rcSrc, &rcDest1, &rcDest2 ) )
{ // draw it together
RECT rcSrcUni; // intersection of the two rectangles
UnionRect( &rcSrcUni, &rcDest1, &rcDest2 );
// step 1: draw back buffer to mix buffer
IntersectRect( &rcSrc, &rcSrcUni, &m_rcRange );
ptDest.x = rcSrc.left - rcSrcUni.left;
ptDest.y = rcSrc.top - rcSrcUni.top;
m_lpMixBuffer->BltSurface( ptDest.x, ptDest.y, DD_GetBackBuffer(), &rcSrc, DDBLTFAST_NOCOLORKEY );
// step 2: draw cursor to mix buffer in new position
ptDest.x = rcDest2.left - rcSrcUni.left;
ptDest.y = rcDest2.top - rcSrcUni.top;
m_lpMixBuffer->BltSurface( ptDest.x, ptDest.y, GetSurface(), &rcSrcFile, GetDrawFlag() );
// step 3: draw mix buffer to front buffer
IntersectRect( &rcSrc, &rcSrcUni, &m_rcRange );
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
rcSrc.left -= rcSrcUni.left, rcSrc.top -= rcSrcUni.top;
rcSrc.right -= rcSrcUni.left;
rcSrc.bottom -= rcSrcUni.top;
m_lpMixBuffer->BltToFront( ptDest, &rcSrc );
}
else
{ // draw it seperatly
// step 1: draw back buffer to front buffer in old position
IntersectRect( &rcSrc, &rcDest1, &m_rcRange );
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
DD_BltSurface( ptDest, DD_GetFrontBuffer(), &rcSrc, DD_GetBackBuffer(), DDBLTFAST_NOCOLORKEY );
// step 2: draw cursor to front buffer in new position
IntersectRect( &rcSrc, &rcDest2, &m_rcRange );
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
rcSrcFile.left -= rcDest2.left - rcSrc.left;
rcSrcFile.top -= rcDest2.top - rcSrc.top;
rcSrcFile.right -= rcDest2.right - rcSrc.right ;
rcSrcFile.bottom -= rcDest2.bottom - rcSrc.bottom;
BltToFront( ptDest, &rcSrcFile );
}
// set last state and last frame
m_nStateLast = m_nState, m_nFrameLast = m_nFrame;
return TRUE;
}
// 应用程序在擦除鼠标光标时应该使用此函数
// erase cursor to front surface, doesn't change frame
// return value : TRUE for has erased
BOOL CDDCursor::Erase()
{
Assert( m_bCreatedC == TRUE );
if( !m_bShow ) return FALSE;
POINT ptPosOld;
RECT rcDest1, rcDest2;
RECT rcSrcFile;
ptPosOld.x = m_ptPos.x;
ptPosOld.y = m_ptPos.y;
// get old destination rectangle
rcDest1 = GetRect();
// get current cursor position
GetCursorPos( &m_ptPos );
// get current destination rectangle
rcDest2 = GetRect();
// get source rectangle of the bitmap file
rcSrcFile.left = m_nFrame*m_szSize.cx;
rcSrcFile.top = m_nState*m_szSize.cy;
rcSrcFile.right = rcSrcFile.left + m_szSize.cx;
rcSrcFile.bottom = rcSrcFile.top + m_szSize.cy;
// calculate if the two rectangles cross
POINT ptDest; // destination position
RECT rcSrc; // source rectangle
// if they cross
if( IntersectRect( &rcSrc, &rcDest1, &rcDest2 ) )
{ // draw it together
RECT rcSrcUni; // intersection of the two rectangles
UnionRect( &rcSrcUni, &rcDest1, &rcDest2 );
// step 1: draw back buffer to mix buffer
IntersectRect( &rcSrc, &rcSrcUni, &m_rcRange );
ptDest.x = rcSrc.left - rcSrcUni.left;
ptDest.y = rcSrc.top - rcSrcUni.top;
m_lpMixBuffer->BltSurface( ptDest.x, ptDest.y, DD_GetBackBuffer(), &rcSrc, DDBLTFAST_NOCOLORKEY );
// step 2: draw cursor to mix buffer in new position
// ptDest.x = rcDest2.left - rcSrcUni.left;
// ptDest.y = rcDest2.top - rcSrcUni.top;
// m_lpMixBuffer->BltSurface( ptDest.x, ptDest.y, GetSurface(), &rcSrcFile, GetDrawFlag() );
// step 3: draw mix buffer to front buffer
IntersectRect( &rcSrc, &rcSrcUni, &m_rcRange );
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
rcSrc.left -= rcSrcUni.left, rcSrc.top -= rcSrcUni.top;
rcSrc.right -= rcSrcUni.left;
rcSrc.bottom -= rcSrcUni.top;
m_lpMixBuffer->BltToFront( ptDest, &rcSrc );
}
else
{ // draw it seperatly
// step 1: draw back buffer to front buffer in old position
IntersectRect( &rcSrc, &rcDest1, &m_rcRange );
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
DD_BltSurface( ptDest, DD_GetFrontBuffer(), &rcSrc, DD_GetBackBuffer(), DDBLTFAST_NOCOLORKEY );
// step 2: draw cursor to front buffer in new position
// IntersectRect( &rcSrc, &rcDest2, &m_rcRange );
// ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
// rcSrcFile.left -= rcDest2.left - rcSrc.left;
// rcSrcFile.top -= rcDest2.top - rcSrc.top;
// rcSrcFile.right -= rcDest2.right - rcSrc.right ;
// rcSrcFile.bottom -= rcDest2.bottom - rcSrc.bottom;
// BltToFront( ptDest, &rcSrcFile );
}
// set last state and last frame
// m_nStateLast = m_nState, m_nFrameLast = m_nFrame;
return TRUE;
}
SIZE CURSOR_szSave;
// 把鼠标显示在背景面上(BackBuffer),特殊情况下使用
// 把背景面保存在m_lpMixBuffer中
// draw corsor to back buffer
// stores back ground to m_lpMixBuffer
// prcCut : 只显示在此矩形区域内,if NULL则不操作
// return value : TRUE for has drew
BOOL CDDCursor::Draw2Back( CONST RECT *prcCut/* = NULL*/ )
{
RECT rcDestOld = GetRect();
RECT rcDest;
RECT rcSrc;
POINT ptDest;
if( IntersectRect( &rcDest, &rcDestOld, prcCut ) )
{
// calc offset
POINT ptTLOff, ptRBOff;
ptTLOff.x = rcDestOld.left - rcDest.left;
ptTLOff.y = rcDestOld.top - rcDest.top;
ptRBOff.x = rcDestOld.right - rcDest.right;
ptRBOff.y = rcDestOld.bottom - rcDest.bottom;
// get source rectangle of the bitmap file
rcSrc.left = m_nFrame*m_szSize.cx;
rcSrc.top = m_nState*m_szSize.cy;
rcSrc.right = rcSrc.left + m_szSize.cx - ptRBOff.x;
rcSrc.bottom = rcSrc.top + m_szSize.cy - ptRBOff.y;
rcSrc.left -= ptTLOff.x;
rcSrc.top -= ptTLOff.y;
// for backup back buffer to mix buffer
ptDest.x = ptDest.y = 0;
CURSOR_szSave.cx = rcDest.right - rcDest.left; // save backup size
CURSOR_szSave.cy = rcDest.bottom - rcDest.top;
// rcDest as rcSrc
DD_BltSurface( ptDest, m_lpMixBuffer->GetSurface(), &rcDest, DD_GetBackBuffer(), DDBLTFAST_NOCOLORKEY );
// draw cursor to back buffer
ptDest.x = rcDest.left, ptDest.y = rcDest.top;
BltToBack( ptDest, &rcSrc );
}
return TRUE;
}
// 把保存的背景面(在m_lpMixBuffer中)放回背景
// restores from m_lpMixBuffer to back buffer
// prcCut : 只显示在此矩形区域内,if NULL则不操作
// return value : TRUE for has drew
BOOL CDDCursor::Restore2Back( CONST RECT *prcCut/* = NULL*/ )
{
RECT rcDestOld = GetRect();
RECT rcDest;
RECT rcSrc;
if( IntersectRect( &rcDest, &rcDestOld, prcCut ) )
{
// get source rectangle of the bitmap file
rcSrc.left = rcSrc.top = 0;
rcSrc.right = CURSOR_szSave.cx;
rcSrc.bottom = CURSOR_szSave.cy;
POINT ptDest;
ptDest.x = rcDest.left, ptDest.y = rcDest.top;
m_lpMixBuffer->BltToBack( ptDest, &rcSrc );
}
return TRUE;
}
#ifdef _CURSOR_OLD_VERSION_
// when draw sprite should draw cursor on it
// used only in DDCompo.cpp, do not use outside
// pRect1, pRect2 : the new and old positoin of the sprite
// return value : if one rectangle is NULL, or did not draw, return FALSE
// Warning : A bug report here
// Draw cursor on any sprite even if cursor is out of range
BOOL CDDCursor::drawSprite( CONST RECT *pRect1, CONST RECT *pRect2 )
{
Assert( m_bCreatedC );
// get cursor rectangle in screen
RECT rcCursor = GetRect();
// get source rectangle of the bitmap file
RECT rcSrcFile;
rcSrcFile.left = m_nFrame*m_szSize.cx;
rcSrcFile.top = m_nState*m_szSize.cy;
rcSrcFile.right = rcSrcFile.left + m_szSize.cx;
rcSrcFile.bottom = rcSrcFile.top + m_szSize.cy;
// get old destination rectangle
RECT rcDest1;
rcDest1.left = pRect1->left;
rcDest1.top = pRect1->top;
rcDest1.right = pRect1->right;
rcDest1.bottom = pRect1->bottom;
// get current destination rectangle
RECT rcDest2;
rcDest2.left = pRect2->left;
rcDest2.top = pRect2->top;
rcDest2.right = pRect2->right;
rcDest2.bottom = pRect2->bottom;
// calculate if the two rectangles cross
POINT ptDest; // destination position
RECT rcSrc; // source rectangle
// if they cross
if( IntersectRect( &rcSrc, &rcDest1, &rcDest2 ) )
{ // draw it together
RECT rcSrcUni; // intersection of the two rectangles
UnionRect( &rcSrcUni, &rcDest1, &rcDest2 );
// step 1: draw back buffer to Sprite buffer
if( !IntersectRect( &rcSrc, &rcSrcUni, &DDC_rcSpriteRange ) )
return FALSE;
ptDest.x = rcSrc.left - rcSrcUni.left;
ptDest.y = rcSrc.top - rcSrcUni.top;
m_lpSpriteBuffer->BltSurface( ptDest.x, ptDest.y, DD_GetBackBuffer(), &rcSrc, DDBLTFAST_NOCOLORKEY );
// step 2: draw cursor to Sprite buffer in new position
IntersectRect( &rcSrc, &rcCursor, &rcSrcUni );
ptDest.x = rcSrc.left - rcSrcUni.left;
ptDest.y = rcSrc.top - rcSrcUni.top;
rcSrc.left = rcSrcFile.left + rcSrc.left - rcCursor.left;
rcSrc.top = rcSrcFile.top + rcSrc.top - rcCursor.top;
rcSrc.right = rcSrcFile.right + rcSrc.right - rcCursor.right ;
rcSrc.bottom = rcSrcFile.bottom + rcSrc.bottom - rcCursor.bottom;
m_lpSpriteBuffer->BltSurface( ptDest.x, ptDest.y, GetSurface(), &rcSrc, GetDrawFlag() );
// step 3: draw Sprite buffer to front buffer
if( !IntersectRect( &rcSrc, &rcSrcUni, &DDC_rcSpriteRange ) )
return FALSE;
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
rcSrc.left -= rcSrcUni.left, rcSrc.top -= rcSrcUni.top;
rcSrc.right -= rcSrcUni.left;
rcSrc.bottom -= rcSrcUni.top;
m_lpSpriteBuffer->BltToFront( ptDest, &rcSrc );
}
else // not fully tested
{ // draw it seperatly
// step 1: draw back buffer to front buffer in old position
if( !IntersectRect( &rcSrc, &rcDest1, &DDC_rcSpriteRange ) )
return FALSE;
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
DD_BltSurface( ptDest, DD_GetFrontBuffer(), &rcSrc, DD_GetBackBuffer(), DDBLTFAST_NOCOLORKEY );
// step 2: draw back buffer to front buffer in new position
if( !IntersectRect( &rcSrc, &rcDest2, &DDC_rcSpriteRange ) )
return FALSE;
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
DD_BltSurface( ptDest, DD_GetFrontBuffer(), &rcSrc, DD_GetBackBuffer(), DDBLTFAST_NOCOLORKEY );
Assert( DDC_pCursor != NULL );
DDC_pCursor->Draw( TRUE );
}
return TRUE;
}// end of drawSprite()
#endif // _CURSOR_OLD_VERSION_
//////////////////////////////
// global functions for cursor
//////////////////////////////
// set the cursor as the current cursor
// pCursor : cursor pointer to be set, set to NULL if you don't need cursor at all
// return : TRUE if the cursor is not null now
BOOL CURSOR_Set( class CDDCursor *pCursor )
{
//if( pCursor == NULL ) return FALSE;
if( DDC_pCursor != NULL )
{
DDC_pCursor->Erase();
DDC_pCursor->SetState(0);
}
DDC_pCursor = pCursor;
return TRUE;
}
// get the current cursor
inline class CDDCursor *CURSOR_Get()
{
return DDC_pCursor;
}
// animate cursor, should be called each cycle
inline void CURSOR_Animate()
{
if( DDC_pCursor != NULL )
DDC_pCursor->Animate();
}
//////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// display functions
//////////////////////////////
#ifdef _CURSOR_OLD_VERSION_
// set sprite moving range
// rcRange : range for sprites to move
// return value : old range for sprites to move
RECT DDC_SetSpriteRange( RECT rcRange )
{
RECT rcRangeOld;
rcRangeOld.left = DDC_rcSpriteRange.left,
rcRangeOld.top = DDC_rcSpriteRange.top,
rcRangeOld.right = DDC_rcSpriteRange.right,
rcRangeOld.bottom = DDC_rcSpriteRange.bottom;
DDC_rcSpriteRange.left = rcRange.left,
DDC_rcSpriteRange.top = rcRange.top,
DDC_rcSpriteRange.right = rcRange.right,
DDC_rcSpriteRange.bottom = rcRange.bottom;
return rcRangeOld;
} // DDC_SetSpriteRange()
#endif // _CURSOR_OLD_VERSION_
#ifdef _CURSOR_OLD_VERSION_
// 应用程序在更新完sprites后应该调用此函数,而不是DD_UpdateScreen()
// this function will redraw cursor automatically
// 两个矩形一般为该sprite在旧位置上的矩形和新位置上的矩形
// update two rectangles from back buffer to front buffer
// if the two rectangles cross, it will combine it to a large rectangle,
// else update two rectangles seperatly
// pRect1, pRect2 : the two rectangles
// return value : if one is NULL, or do not draw, return FALSE
BOOL DDC_UpdateSprite( CONST RECT *pRect1, CONST RECT *pRect2 )
{
// update whole screen from back buffer to front buffer
if( pRect1 == NULL || pRect2 == NULL )
return FALSE;
// calculate if the two rectangles cross
POINT ptDest; // destination position
RECT rcSrc; // source rectangle
// update cursor if need
Assert( DDC_pCursor != NULL );
RECT rcCursor = DDC_pCursor->GetRect();
RECT rcDest;
if( IntersectRect( &rcDest, pRect1, &rcCursor) ||
IntersectRect( &rcDest, pRect2, &rcCursor) )
{
// should draw cursor on it
return DDC_pCursor->drawSprite( pRect1, pRect2 );
}
else
{
// need not to draw cursor on it
// if they cross
if( IntersectRect( &rcSrc, pRect1, pRect2 ) )
{ // draw it together
RECT rcSrcUni; // intersection of the two rectangles
UnionRect( &rcSrcUni, pRect1, pRect2 );
// step 1: draw back buffer to front buffer
if( !IntersectRect( &rcSrc, &rcSrcUni, &DDC_rcSpriteRange ) )
return FALSE;
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
DD_BltSurface( ptDest, DD_GetFrontBuffer(), &rcSrc, DD_GetBackBuffer(), DDBLTFAST_NOCOLORKEY );
}
else
{ // draw it seperatly
// step 1: draw back buffer to front buffer in old position
if( !IntersectRect( &rcSrc, pRect1, &DDC_rcSpriteRange ) )
return FALSE;
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
DD_BltSurface( ptDest, DD_GetFrontBuffer(), &rcSrc, DD_GetBackBuffer(), DDBLTFAST_NOCOLORKEY );
// step 2: draw cursor to front buffer in new position
if( !IntersectRect( &rcSrc, pRect2, &DDC_rcSpriteRange ) )
return FALSE;
ptDest.x = rcSrc.left, ptDest.y = rcSrc.top;
DD_BltSurface( ptDest, DD_GetFrontBuffer(), &rcSrc, DD_GetBackBuffer(), DDBLTFAST_NOCOLORKEY );
}
}
return TRUE;
} // DDC_UpdateSprite()
#endif // _CURSOR_OLD_VERSION_
// when need update, should use this functions instead of DD_UpdateScreen() in DDAPI.h
// update only one rectangle of back buffer to front buffer
// pRect : rectangle to be update
void DDC_UpdateScreen( RECT *pRect/*=NULL*/ )
{
if( DDC_pCursor != NULL )
DDC_pCursor->Draw2Back( pRect );
DD_UpdateScreen( pRect );
if( DDC_pCursor != NULL )
DDC_pCursor->Restore2Back( pRect );
} // DDC_UpdateScreen()
#ifdef _CURSOR_OLD_VERSION_
// set max size of sprites
// in order to take effect, you must call this function before CDDCursor::Load()
// szMax : max size of sprites
// return value : old max size of sprites
SIZE DDC_SetSpriteMaxSize( SIZE szMax )
{
SIZE szMaxOld;
szMaxOld.cx = DDC_szSpriteMax.cx;
szMaxOld.cy = DDC_szSpriteMax.cy;
DDC_szSpriteMax.cx = szMax.cx;
DDC_szSpriteMax.cy = szMax.cy;
return szMaxOld;
} // DDC_SetSpriteMaxSize()
#endif // _CURSOR_OLD_VERSION_
//////////////////////////////
// sub-draw functions
//////////////////////////////
// draw rectangle on screen, by using DC
// pRect : rectangle to draw
// color : color to draw
// bFront : TRUE for draw it on front buffer
// return value : TRUE if succeeded
BOOL DDC_FrameRect( CONST RECT *pRect, COLORREF color, BOOL bFront/*=FALSE*/ )
{
HDC hdc;
LPDIRECTDRAWSURFACE2 lpDDS=NULL;
if( bFront ) lpDDS = DD_GetFrontBuffer();
else lpDDS = DD_GetBackBuffer();
if( lpDDS->GetDC(&hdc) != DD_OK )
return FALSE;
HBRUSH hbr = CreateSolidBrush( color );
FrameRect( hdc, pRect, hbr );
DeleteObject( HBRUSH(hbr) );
lpDDS->ReleaseDC( hdc );
return TRUE;
}
// draw rectangle on one surface, by using DC
// pRect : rectangle to draw
// color : color to draw
// bFront : TRUE for draw it on front buffer
// return value : TRUE if succeeded
BOOL DDC_FrameRect( LPDIRECTDRAWSURFACE2 lpDDS, CONST RECT *pRect, COLORREF color )
{
HDC hdc;
if( lpDDS->GetDC(&hdc) != DD_OK )
return FALSE;
HBRUSH hbr = CreateSolidBrush( color );
FrameRect( hdc, pRect, hbr );
DeleteObject( HBRUSH(hbr) );
lpDDS->ReleaseDC( hdc );
return TRUE;
}
//////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -