📄 didevimg.cpp
字号:
}
if( 0 == ::GetObject( hbmpRender, sizeof( DIBSECTION ), &info ) )
{
hr = E_FAIL;
goto LCleanReturn;
}
SelectObject( hdcRender, hbmpRender );
SelectObject( hdcRender, m_hFont );
SetBkMode( hdcRender, TRANSPARENT );
FillBackground( hbmpRender, m_BkColor );
// Create a bitmap to store the alpha channel for the bitmap. Since GDI
// doesn't support alpha information, everything is drawn fully transparent.
// As a workaround, whenever a 2D method is called on the render dc,
// the same method will be called on the alpha dc. Before transfering the
// image to the provided surface, the transparency information will be
// restored from the alpha bitmap.
hbmpAlpha = CreateDIBSection( hdcAlpha, &bmi, DIB_RGB_COLORS, NULL, NULL, NULL );
if( NULL == hbmpAlpha )
{
hr = DIERR_OUTOFMEMORY;
goto LCleanReturn;
}
// Clear the alpha channel
DIBSECTION infoAlpha;
if( 0 == ::GetObject( hbmpAlpha, sizeof(DIBSECTION), &infoAlpha ) )
{
hr = E_FAIL;
goto LCleanReturn;
}
ZeroMemory( infoAlpha.dsBm.bmBits, infoAlpha.dsBm.bmWidthBytes * infoAlpha.dsBm.bmHeight );
SelectObject( hdcAlpha, hbmpAlpha );
SetBkMode( hdcAlpha, TRANSPARENT );
SetTextColor( hdcAlpha, RGB(255, 255, 255) );
SelectObject( hdcAlpha, GetStockObject( WHITE_PEN ) );
SelectObject( hdcAlpha, m_hFont );
// Draw callout and object text
for( i=0; i < m_dwNumObjects; i++ )
{
COLORREF crNorm, crHigh, crCur;
DIDICallout *pCallout = m_apObject[i]->GetCallout( m_dwActiveView );
DIDIOverlay *pOverlay = m_apObject[i]->GetOverlay( m_dwActiveView );
MAXSTRING strCallout = {0};
MAXSTRING strObject = {0};
RECT rcFill = {0};
// Callout may be invisible
if( DIDICOS_INVISIBLE & m_apObject[i]->GetCalloutState() )
continue;
if( IsRectEmpty( &pOverlay->rcScaled ) ||
IsRectEmpty( &pCallout->rcScaled ) )
continue;
m_apObject[i]->GetCalloutText( strCallout, MAX_PATH );
m_apObject[i]->GetName( strObject, MAX_PATH );
m_apObject[i]->GetCalloutColors( &crNorm, &crHigh );
crCur = ( DIDICOS_HIGHLIGHTED & m_apObject[i]->GetCalloutState() ) ? crHigh : crNorm;
SetTextColor( hdcRender, crNorm );
DWORD dwFlags = DT_TOP | DT_END_ELLIPSIS | DT_NOCLIP;
// Get the fill rect
rcFill = pOverlay->rcScaled;
DrawText( hdcRender, strObject, lstrlen( strObject ),
&rcFill, dwFlags | DT_CALCRECT );
// Position the fill rect
rcFill.left += pOverlay->rcScaled.right - rcFill.right;
rcFill.right += pOverlay->rcScaled.right - rcFill.right;
// Inflate the fill 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 );
// Draw the object text
DrawText( hdcRender, strObject, lstrlen( strObject ),
&(pOverlay->rcScaled), dwFlags | DT_RIGHT );
if( hdcAlpha )
DrawText( hdcAlpha, strObject, lstrlen( strObject ),
&(pOverlay->rcScaled), dwFlags | DT_RIGHT );
SetTextColor( hdcRender, crCur );
// Get the fill rect
rcFill = pCallout->rcScaled;
DrawText( hdcRender, strCallout, lstrlen( strCallout ),
&rcFill, dwFlags | DT_CALCRECT );
// Inflate the fill 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 );
// Draw the callout text
DrawText( hdcRender, strCallout, lstrlen( strCallout ),
&(pCallout->rcScaled), dwFlags | DT_LEFT );
if( hdcAlpha )
DrawText( hdcAlpha, strCallout, lstrlen( strCallout ),
&(pCallout->rcScaled), dwFlags | DT_LEFT );
// 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 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( hbmpRender, 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:
DeleteDC( hdcRender );
DeleteDC( hdcAlpha );
if( hbmpAlpha )
DeleteObject( hbmpAlpha );
if( hbmpRender )
DeleteObject( hbmpRender );
return hr;
}
//-----------------------------------------------------------------------------
// Name: RenderToTarget
// Desc: Renders an image of the device and its callouts
//-----------------------------------------------------------------------------
HRESULT CDIDevImage::RenderToTarget( LPVOID pvTarget, DIDIRENDERTARGET eTarget )
{
HRESULT hr = DI_OK;
UINT i = 0; // Loop variable
RECT rcBitmap = {0};
HDC hdcRender = NULL;
HDC hdcAlpha = NULL;
DIBSECTION info = {0};
LPBYTE pSavedPixels = NULL;
LPBYTE pCleanPixels = NULL;
HBITMAP hbmpAlpha = NULL;
BITMAPINFO bmi = {0};
// Verify initialization
if( false == m_bInitialized )
return DIERR_NOTINITIALIZED;
// Verify parameters
if( NULL == pvTarget )
return DIERR_INVALIDPARAM;
// Sanity check
if( m_dwActiveView >= m_dwNumViews )
return E_FAIL;
// Load images if not loaded already
if( NULL == m_ahImages[ m_dwActiveView ] )
{
// File UI not yet loaded
if( FAILED( hr = LoadImages() ) )
return hr;
}
// Get information about the background image.
if( 0 == ::GetObject( m_ahImages[ m_dwActiveView ], sizeof(DIBSECTION), &info ) )
return E_FAIL;
// Allocate space for the saved background images
pSavedPixels = new BYTE[ info.dsBm.bmWidthBytes * info.dsBm.bmHeight ];
if( NULL == pSavedPixels )
{
hr = DIERR_OUTOFMEMORY;
goto LCleanReturn;
}
pCleanPixels = new BYTE[ info.dsBm.bmWidthBytes * info.dsBm.bmHeight ];
if( NULL == pCleanPixels )
{
// Could not create a copy of the background image; release memory
// here to avoid using unitialized pixels during cleanup.
SAFE_DELETE_ARRAY( pSavedPixels );
hr = DIERR_OUTOFMEMORY;
goto LCleanReturn;
}
// Save the background
CopyMemory( pSavedPixels, info.dsBm.bmBits,
info.dsBm.bmWidthBytes * info.dsBm.bmHeight );
// Draw overlays
for( i=0; i < m_dwNumObjects; i++ )
{
DIDIOverlay *pOverlay = m_apObject[i]->GetOverlay( m_dwActiveView );
if( DIDICOS_HIGHLIGHTED & m_apObject[i]->GetCalloutState() )
{
// Draw overlay
if( pOverlay->hImage )
ApplyOverlay( m_ahImages[ m_dwActiveView ], &pOverlay->rcScaled, pOverlay->hImage );
}
}
// Before drawing callouts and lines on top of the composed image, save
// a copy of the image bits. This will allow us to erase portions of lines
// which intersect with the callout text.
CopyMemory( pCleanPixels, info.dsBm.bmBits,
info.dsBm.bmWidthBytes * info.dsBm.bmHeight );
// Load the background image into a device context for rendering
hdcRender = CreateCompatibleDC( NULL );
SelectObject( hdcRender, m_ahImages[ m_dwActiveView ] );
SelectObject( hdcRender, m_hFont );
SetBkMode( hdcRender, TRANSPARENT );
SetBkColor( hdcRender, CRFromColor(m_BkColor) );
hdcAlpha = CreateCompatibleDC( NULL );
// Create a bitmap to store the alpha channel for the bitmap. Since GDI
// doesn't support alpha information, everything is drawn fully transparent.
// As a workaround, whenever a 2D method is called on the render dc,
// the same method will be called on the alpha dc. Before transfering the
// image to the provided surface, the transparency information will be
// restored from the alpha bitmap.
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = info.dsBm.bmWidth;
bmi.bmiHeader.biHeight = - (int) info.dsBm.bmHeight; // top-down
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
hbmpAlpha = CreateDIBSection( hdcAlpha, &bmi, DIB_RGB_COLORS, NULL, NULL, NULL );
if( NULL == hbmpAlpha )
{
hr = DIERR_OUTOFMEMORY;
goto LCleanReturn;
}
// Clear the alpha channel
DIBSECTION infoAlpha;
if( 0 == ::GetObject( hbmpAlpha, sizeof(DIBSECTION), &infoAlpha ) )
{
hr = E_FAIL;
goto LCleanReturn;
}
ZeroMemory( infoAlpha.dsBm.bmBits, infoAlpha.dsBm.bmWidthBytes * infoAlpha.dsBm.bmHeight );
SelectObject( hdcAlpha, hbmpAlpha );
SetBkMode( hdcAlpha, TRANSPARENT );
SetTextColor( hdcAlpha, RGB(255, 255, 255) );
SelectObject( hdcAlpha, GetStockObject( WHITE_PEN ) );
SelectObject( hdcAlpha, m_hFont );
// Draw callout lines
for( i=0; i < m_dwNumObjects; i++ )
{
COLORREF crNorm, crHigh, crCur;
POINT aptArrow[2] = {0};
BOOL bDrawArrow = FALSE;
// Get the current callout
DIDICallout *pCallout = m_apObject[i]->GetCallout( m_dwActiveView );
// Callout may be invisible
if( DIDICOS_INVISIBLE & m_apObject[i]->GetCalloutState() )
continue;
// Retrieve normal/highlighted colors
m_apObject[i]->GetCalloutColors( &crNorm, &crHigh );
// Set the current color based on callout state
crCur = ( DIDICOS_HIGHLIGHTED & m_apObject[i]->GetCalloutState() ) ? crHigh : crNorm;
DeleteObject( SelectObject( hdcRender, CreatePen( PS_SOLID, 3, CRFromColor(m_BkColor) ) ) );
DeleteObject( SelectObject( hdcAlpha, CreatePen( PS_SOLID, 3, RGB(255, 255, 255) ) ) );
// 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( UINT 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( pCallout->dwNumPoints >= 2 )
{
DWORD dwEnd = pCallout->dwNumPoints-1;
POINT p1 = pCallout->aptLineScaled[ dwEnd ];
POINT p2 = pCallout->aptLineScaled[ dwEnd-1 ];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -