📄 didevimg.cpp
字号:
aptArrow[0] = aptArrow[1] = p1;
bDrawArrow = TRUE;
aptArrow[0].x -= 1;
aptArrow[0].y -= 1;
aptArrow[1].x += 1;
aptArrow[1].y += 1;
// Adjust arrow points based on line orientation
if( p1.y == p2.y )
{
if( p2.x < p1.x )
aptArrow[1].x -= 2;
else
aptArrow[0].x += 2;
}
else if( p1.x == p2.x )
{
if( p2.y < p1.y )
aptArrow[1].y -= 2;
else
aptArrow[0].y += 2;
}
else
{
// This is a diagonal line. Skip the arrow endpoint.
bDrawArrow = FALSE;
}
if( bDrawArrow )
{
MoveToEx( hdcRender, aptArrow[0].x, aptArrow[0].y, NULL );
LineTo( hdcRender, aptArrow[1].x, aptArrow[1].y );
MoveToEx( hdcAlpha, aptArrow[0].x, aptArrow[0].y, NULL );
LineTo( hdcAlpha, aptArrow[1].x, aptArrow[1].y );
}
}
// Select a new pen into the DC based on current color
DeleteObject( SelectObject( hdcRender, CreatePen( PS_SOLID, 1, crCur ) ) );
DeleteObject( SelectObject( hdcAlpha, GetStockObject( WHITE_PEN ) ) );
// Draw callout lines
MoveToEx( hdcRender, pCallout->aptLineScaled[0].x, pCallout->aptLineScaled[0].y, NULL );
MoveToEx( hdcAlpha, pCallout->aptLineScaled[0].x, pCallout->aptLineScaled[0].y, NULL );
for( j=1; j < pCallout->dwNumPoints; j++ )
{
LineTo( hdcRender, pCallout->aptLineScaled[j].x, pCallout->aptLineScaled[j].y );
LineTo( hdcAlpha, pCallout->aptLineScaled[j].x, pCallout->aptLineScaled[j].y );
}
// Draw arrow ends
if( bDrawArrow )
{
DWORD dwEnd = pCallout->dwNumPoints-1;
SetPixel( hdcRender, aptArrow[0].x, aptArrow[0].y, crCur );
SetPixel( hdcRender, aptArrow[1].x, aptArrow[1].y, crCur );
SetPixel( hdcRender, pCallout->aptLineScaled[ dwEnd ].x,
pCallout->aptLineScaled[ dwEnd ].y, crCur );
SetPixel( hdcAlpha, aptArrow[0].x, aptArrow[0].y, RGB(255, 255, 255) );
SetPixel( hdcAlpha, aptArrow[1].x, aptArrow[1].y, RGB(255, 255, 255) );
SetPixel( hdcAlpha, pCallout->aptLineScaled[ dwEnd ].x,
pCallout->aptLineScaled[ dwEnd ].y, RGB(255, 255, 255) );
}
}
// Free the pen resource
DeleteObject( SelectObject( hdcRender, GetStockObject( WHITE_PEN ) ) );
DeleteObject( SelectObject( hdcAlpha, GetStockObject( WHITE_PEN ) ) );
// Draw callout text
for( i=0; i < m_dwNumObjects; i++ )
{
COLORREF crNorm, crHigh, crCur;
RECT rcFill;
DIDICallout *pCallout = m_apObject[i]->GetCallout( m_dwActiveView );
MAXSTRING strCallout = {0};
// Callout may be invisible
if( DIDICOS_INVISIBLE & m_apObject[i]->GetCalloutState() )
continue;
m_apObject[i]->GetCalloutText( strCallout, MAX_PATH-4 );
m_apObject[i]->GetCalloutColors( &crNorm, &crHigh );
if( IsRectEmpty( &pCallout->rcScaled ) )
continue;
// Draw callouts
DWORD dwFormat = DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOCLIP;
// Get text dimensions
rcFill = pCallout->rcScaled;
DrawText( hdcRender, strCallout, lstrlen( strCallout ),
&rcFill, dwFormat | DT_CALCRECT | DT_MODIFYSTRING );
// Horizontal alignment
if( pCallout->dwTextAlign & DIDAL_CENTERED )
{
dwFormat |= DT_CENTER;
OffsetRect( &rcFill, (pCallout->rcScaled.right - rcFill.right) / 2, 0 );
}
else if( pCallout->dwTextAlign & DIDAL_RIGHTALIGNED )
{
dwFormat |= DT_RIGHT;
OffsetRect( &rcFill, (pCallout->rcScaled.right - rcFill.right ), 0 );
}
else
{
dwFormat |= DT_LEFT;
}
// Vertical alignment
if( pCallout->dwTextAlign & DIDAL_MIDDLE )
{
dwFormat |= DT_VCENTER;
OffsetRect( &rcFill, 0, (pCallout->rcScaled.bottom - rcFill.bottom) / 2 );
}
else if( pCallout->dwTextAlign & DIDAL_BOTTOMALIGNED )
{
dwFormat |= DT_BOTTOM;
OffsetRect( &rcFill, 0, (pCallout->rcScaled.bottom - rcFill.bottom) );
}
else
{
dwFormat |= DT_TOP;
}
// First replace the background area behind the text to cover up
// intersecting lines
// Pad the returned rect
InflateRect( &rcFill, 5, 5 );
// But make sure the rect still fits on the screen
rcFill.left = max( rcFill.left, 0 );
rcFill.top = max( rcFill.top, 0 );
rcFill.right = min( rcFill.right, info.dsBm.bmWidth );
rcFill.bottom = min( rcFill.bottom, info.dsBm.bmHeight );
RestoreRect( m_ahImages[ m_dwActiveView ], &rcFill, pCleanPixels );
if( hdcAlpha )
FillRect( hdcAlpha, &rcFill, (HBRUSH) GetStockObject( BLACK_BRUSH ) );
// Fill behind the text
SetTextColor( hdcRender, CRFromColor(m_BkColor) );
for( int x = -1; x <= 1; x++ )
{
for( int y = -1; y <= 1; y++ )
{
RECT rcText = pCallout->rcScaled;
OffsetRect( &rcText, x, y );
DrawText( hdcRender, strCallout, lstrlen( strCallout ),
&rcText, dwFormat );
DrawText( hdcAlpha, strCallout, lstrlen( strCallout ),
&rcText, dwFormat );
}
}
// Now draw the actual text
crCur = ( DIDICOS_HIGHLIGHTED & m_apObject[i]->GetCalloutState() ) ? crHigh : crNorm;
SetTextColor( hdcRender, crCur );
DrawText( hdcRender, strCallout, lstrlen( strCallout ),
&(pCallout->rcScaled), dwFormat );
DrawText( hdcAlpha, strCallout, lstrlen( strCallout ),
&(pCallout->rcScaled), dwFormat );
// If the TOOLTIP flag is set and the callout text doesn't fit within
// the scaled rect, we need to draw the full text
if( DIDICOS_TOOLTIP & m_apObject[i]->GetCalloutState() )
{
SIZE TextSize = {0};
// This string was modified by the first call to draw text, so we
// need to get a fresh copy
m_apObject[i]->GetCalloutText( strCallout, MAX_PATH-4 );
GetTextExtentPoint32( hdcRender, strCallout, lstrlen( strCallout ), &TextSize );
if( TextSize.cx > ( pCallout->rcScaled.right - pCallout->rcScaled.left ) )
{
// Yep, the text is too big and is marked as a tooltip candidate.
RECT rcBitmap = { 0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight };
DrawTooltip( hdcRender, hdcAlpha, strCallout, &rcBitmap, &(pCallout->rcScaled),
CRFromColor( m_BkColor ), crNorm, crHigh );
}
}
}
// Finalize all rendering
GdiFlush();
// Copy the freshly rendered image to the render target
switch( eTarget )
{
case DIDIRT_SURFACE:
// Since the image is being transfered to a Direct3D surface, the stored
// alpha information could be used.
ApplyAlphaChannel( m_ahImages[ m_dwActiveView ], hbmpAlpha, ( (m_BkColor & ALPHA_MASK) == ALPHA_MASK ) );
rcBitmap.right = info.dsBm.bmWidth;
rcBitmap.bottom = info.dsBm.bmHeight;
hr = D3DXLoadSurfaceFromMemory( (LPDIRECT3DSURFACE9) pvTarget,
NULL, NULL, info.dsBm.bmBits,
D3DFMT_A8R8G8B8,
info.dsBm.bmWidthBytes,
NULL, &rcBitmap,
D3DX_FILTER_NONE, 0 );
break;
case DIDIRT_DC:
BitBlt( (HDC) pvTarget, 0, 0, info.dsBm.bmWidth, info.dsBm.bmHeight,
hdcRender, 0, 0, SRCCOPY );
break;
default:
// Invalid render target
hr = DIERR_INVALIDPARAM;
goto LCleanReturn;
}
LCleanReturn:
// Restore the background
if( pSavedPixels )
CopyMemory( info.dsBm.bmBits, pSavedPixels, info.dsBm.bmWidthBytes * info.dsBm.bmHeight );
DeleteDC( hdcRender );
DeleteDC( hdcAlpha );
DeleteObject( hbmpAlpha );
delete [] pSavedPixels;
delete [] pCleanPixels;
return hr;
}
//-----------------------------------------------------------------------------
// Name: AddObject
// Desc: Adds an object to the current list according to object ID. If an
// object with the given ID already exists, a pointer to it returned.
// Otherwise, a new object is created and a pointer to the new object
// is returned. Returns NULL if memory couldn't be allocated.
//-----------------------------------------------------------------------------
HRESULT CDIDevImage::AddObject( DWORD dwID )
{
CDIDIObject* pObject = NULL;
// Search through current objects
if( GetObject( dwID ) )
return DI_OK;
// Did not find object. Create a new object, and store pointer
pObject = new CDIDIObject( dwID, m_dwNumViews );
if( NULL == pObject )
return DIERR_OUTOFMEMORY;
m_apObject[m_dwNumObjects++] = pObject;
return DI_OK;
}
//-----------------------------------------------------------------------------
// Name: GetObject
// Desc: If an object with given ID exist, a pointer to it is returned
//-----------------------------------------------------------------------------
CDIDIObject* CDIDevImage::GetObject( DWORD dwID )
{
for( UINT i=0; i < m_dwNumObjects; i++ )
{
if( m_apObject[i]->GetID() == dwID )
return m_apObject[i];
}
return NULL;
}
//-----------------------------------------------------------------------------
// Name: LoadImageInfo
// Desc: helper function to retrieve callout / image data from
// DirectInput
//-----------------------------------------------------------------------------
HRESULT CDIDevImage::LoadImageInfo( LPDIRECTINPUTDEVICE8 pDIDevice )
{
HRESULT hr;
DWORD dwBufferCount = 0;
DIDEVICEIMAGEINFOHEADER dihImageHeader = {0};
DIDEVICEIMAGEINFO *pInfo = NULL;
// properly initialize the structure before it can be used
dihImageHeader.dwSize = sizeof( DIDEVICEIMAGEINFOHEADER );
dihImageHeader.dwSizeImageInfo = sizeof( DIDEVICEIMAGEINFO );
// since m_dihImageHeader.dwBufferSize is 0, this call serves to determine
// the minimum buffer size required to hold information for all the images
hr = pDIDevice->GetImageInfo( &dihImageHeader );
if( FAILED(hr) )
return hr;
// at this point, m_lpDidImgHeader->dwBufferUsed has been set by
// the GetImageInfo method to minimum buffer size needed, so allocate.
dihImageHeader.dwBufferSize = dihImageHeader.dwBufferUsed;
dihImageHeader.lprgImageInfoArray = (DIDEVICEIMAGEINFO*) new BYTE[dihImageHeader.dwBufferSize];
// make sure memory has been allocated
if( NULL == dihImageHeader.lprgImageInfoArray )
return DIERR_OUTOFMEMORY;
// now that the dwBufferSize has been filled, and lprgImageArray allocated,
// we call GetImageInfo again to get the image data
hr = pDIDevice->GetImageInfo( &dihImageHeader );
if( FAILED(hr) )
goto LCleanReturn;
// Allocate space for all the object/callouts/overlays
m_apObject = new CDIDIObject* [dihImageHeader.dwcButtons +
dihImageHeader.dwcAxes +
dihImageHeader.dwcPOVs];
if( NULL == m_apObject )
{
hr = DIERR_OUTOFMEMORY;
goto LCleanReturn;
}
m_dwNumViews = dihImageHeader.dwcViews;
// Allocate space for background images
m_atszImagePath = new TCHAR[m_dwNumViews][MAX_PATH];
if( NULL == m_atszImagePath )
{
hr = DIERR_OUTOFMEMORY;
goto LCleanReturn;
}
ZeroMemory( m_atszImagePath, sizeof(m_atszImagePath) );
m_ahImages = new HBITMAP[m_dwNumViews];
if( NULL == m_ahImages )
{
hr = DIERR_OUTOFMEMORY;
goto LCleanReturn;
}
ZeroMemory( m_ahImages, sizeof(m_ahImages) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -