// IconCache.cpp : Implementation of cIconCache #include "stdafx.h" #include "Inject.h" #include "IconCache.h" #include "Manager.h" //Moputu - 05172002: Added long lColor to make icons with different colored borders unique. bool cIconCache::findIcon( HMODULE hMod, DWORD dwFile, cIconCache::cIconBuffer *&pBuffer, int &nIndex, long lColor ) { for( cIconBufferList::iterator i = m_icons.begin(); i != m_icons.end(); ) { VARIANT_BOOL bLost; i->m_pSurface->get_WasLost( &bLost ); if( bLost ) { i = m_icons.erase( i ); continue; } // Search inside this buffer for( cIDList::iterator j = i->m_icons.begin(); j != i->m_icons.end(); ++ j ) { //if( j->m_hMod == hMod && j->m_dwID == dwFile ) // Original Code if( j->m_hMod == hMod && j->m_dwID == dwFile && j->m_lBColor == lColor ) { // We found the icon, return happy pBuffer = &( *i ); nIndex = j - i->m_icons.begin(); return true; } } ++ i; } // Icon not found return false; } void cIconCache::findFreeSlot( cIconBuffer *&pBuffer, int &nIndex ) { // First find a buffer with an unused icon slot, note that we test // the buffers for( cIconBufferList::iterator i = m_icons.begin(); i != m_icons.end(); ) { VARIANT_BOOL bLost; i->m_pSurface->get_WasLost( &bLost ); if( bLost ) { i = m_icons.erase( i ); continue; } if( i->m_icons.size() < ( m_nEdge * m_nEdge ) ) break; ++ i; } if( i == m_icons.end() ) { // There were no surfaces with free slots, make a new one cIconBuffer buf; buf.m_icons.reserve( m_nEdge * m_nEdge ); SIZE sz = { m_szIcon.cx * m_nEdge, m_szIcon.cy * m_nEdge }; cManager::_p->CreateCanvas( &sz, &buf.m_pSurface ); m_icons.push_back( buf ); // Reset to last entry i = -- m_icons.end(); } pBuffer = &( *i ); nIndex = i->m_icons.size(); } //Modified by Moputu 05/12/2002 to allow the replacement of icon border colors. bool cIconCache::loadIcon( DWORD dwFile, cIconCache::cIconBuffer *&pBuffer, int &nIndex, long lColor ) { findFreeSlot( pBuffer, nIndex ); struct cColorImage { DWORD m_dwID, m_dwX, m_dwY; }; try { cDatFile::cFile icon = cManager::_p->m_portal.getFile( dwFile ); cColorImage header; icon.read( reinterpret_cast< BYTE * >( &header ), sizeof( cColorImage ) ); int nXScale, nYScale; if( header.m_dwX % m_szIcon.cx != 0 ) { // Bad size - only linear filtering here _ASSERT( FALSE ); return false; } nXScale = header.m_dwX / m_szIcon.cx; if( header.m_dwY % m_szIcon.cy != 0 ) { // Bad size - only linear filtering here _ASSERT( FALSE ); return false; } nYScale = header.m_dwY / m_szIcon.cy; // Can't fail now, transfering bits to the buffer POINT ptIconOrg = { ( nIndex % m_nEdge ) * m_szIcon.cx, ( nIndex / m_nEdge ) * m_szIcon.cy }; RECT rcSrc = { ptIconOrg.x, ptIconOrg.y, ptIconOrg.x + m_szIcon.cx, ptIconOrg.y + m_szIcon.cy }; DDSURFACEDESC2 desc; desc.dwSize = sizeof( DDSURFACEDESC2 ); CComPtr< IDirectDrawSurface4 > pSurface; pBuffer->m_pSurface->GetSurface( IID_IDirectDrawSurface4, reinterpret_cast< void ** >( &pSurface ) ); pSurface->Lock( &rcSrc, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL ); BYTE srcLine[ 3 * 64 ], *pEndLine = srcLine + 3 * header.m_dwX; { for( int i = 0; i < m_szIcon.cy; ++ i ) { // Read in a line icon.read( srcLine, 3 * header.m_dwX ); icon.skip( 3 * header.m_dwX * ( nYScale - 1 ) ); WORD *pwDest = reinterpret_cast< WORD * >( reinterpret_cast< BYTE * >( desc.lpSurface ) + desc.lPitch * i ); for( BYTE *pbSrc = srcLine; pbSrc != pEndLine; pbSrc += 3 * nXScale, ++ pwDest ) { // Check for black (transparent) if( ( pbSrc[ 0 ] == 0 && pbSrc[ 1 ] == 0 && pbSrc[ 2 ] == 0 ) || ( pbSrc[ 0 ] == 255 && pbSrc[ 1 ] == 255 && pbSrc[ 2 ] == 255 ) ) // *pwDest = 0x07FF; // Original code if( pbSrc[ 0 ] == 255 && pbSrc[ 1 ] == 255 && pbSrc[ 2 ] == 255 ) //Check for White (border) { if ( lColor == -1 ) // No argument was passed, treat it like the original code would have. { *pwDest = 0x07FF; } else //Replace with specified color. { pBuffer->m_pSurface->DownMixRGB((BYTE)lColor, (BYTE)(lColor >> 8), (BYTE)(lColor >> 16), pwDest); } } else { *pwDest = 0x07FF; } else { pBuffer->m_pSurface->DownMixRGB(pbSrc[0], pbSrc[1], pbSrc[2], pwDest); } } } } pSurface->Unlock( &rcSrc ); cIconID iid = { NULL, dwFile, lColor }; //Moputu - 05172002: Added lColor to make icons with different colored borders unique. pBuffer->m_icons.push_back( iid ); // Survived the encounter return true; } catch( ... ) { // Failure, return false at end } // File not found, fail _ASSERT( FALSE ); return false; } bool cIconCache::loadIconResource( HMODULE hMod, DWORD dwResourceID, cIconBuffer *&pBuffer, int &nIndex, long lColor ) { HICON hIcon = reinterpret_cast< HICON >( ::LoadImage( hMod, MAKEINTRESOURCE( dwResourceID ), IMAGE_ICON, m_szIcon.cx, m_szIcon.cy, LR_DEFAULTCOLOR ) ); if( hIcon == NULL ) return false; findFreeSlot( pBuffer, nIndex ); // TODO: Write a fast version of this function, use GDI for now HDC hdc; pBuffer->m_pSurface->GetDC( &hdc ); HBRUSH br = ::CreateSolidBrush( RGB( 0, 255, 255 ) ); POINT ptIconOrg = { ( nIndex % m_nEdge ) * m_szIcon.cx, ( nIndex / m_nEdge ) * m_szIcon.cy }; RECT rcSrc = { ptIconOrg.x, ptIconOrg.y, ptIconOrg.x + m_szIcon.cx, ptIconOrg.y + m_szIcon.cy }; ::FillRect( hdc, &rcSrc, br ); ::DrawIconEx( hdc, ptIconOrg.x, ptIconOrg.y, hIcon, m_szIcon.cx, m_szIcon.cy, 0, NULL, DI_NORMAL ); ::DeleteObject( br ); pBuffer->m_pSurface->ReleaseDC(); ::DestroyIcon( hIcon ); cIconID iid = { hMod, dwResourceID, lColor }; //Moputu - 05172002: Added long lColor to make icons with different colored borders unique. pBuffer->m_icons.push_back( iid ); return true; } void cIconCache::drawIcon( LPPOINT pPos, ICanvas *pDest, cIconBuffer *pBuffer, int nIndex ) { _ASSERTE( pPos != NULL ); _ASSERTE( pDest != NULL ); _ASSERTE( pBuffer != NULL ); _ASSERTE( nIndex >= 0 && nIndex < ( m_nEdge * m_nEdge ) ); POINT ptIconOrg = { ( nIndex % m_nEdge ) * m_szIcon.cx, ( nIndex / m_nEdge ) * m_szIcon.cy }; RECT rcSrc = { ptIconOrg.x, ptIconOrg.y, ptIconOrg.x + m_szIcon.cx, ptIconOrg.y + m_szIcon.cy }; pDest->Blt( &rcSrc, pBuffer->m_pSurface, pPos ); } ///////////////////////////////////////////////////////////////////////////// // cIconCache STDMETHODIMP cIconCache::DrawIcon( LPPOINT ppt, long nFile, long nModule, ICanvas *pCanvas ) { _ASSERTE( ppt != NULL ); _ASSERTE( pCanvas != NULL ); cIconBuffer *pBuffer; int nIndex; // GKusnick: Handle no-icon case without asserting. if (nModule == 0 && nFile == 0) return S_OK; if( !findIcon( reinterpret_cast< HMODULE >( nModule ), *reinterpret_cast< DWORD* >( &nFile ), pBuffer, nIndex ) ) { if( nModule == 0 ) { if( !loadIcon( *reinterpret_cast< DWORD* >( &nFile ), pBuffer, nIndex ) ) return E_FAIL; } else { if( !loadIconResource( reinterpret_cast< HMODULE >( nModule ), *reinterpret_cast< DWORD* >( &nFile ), pBuffer, nIndex ) ) return E_FAIL; } } drawIcon( ppt, pCanvas, pBuffer, nIndex ); return S_OK; } STDMETHODIMP cIconCache::DrawIconEx( LPPOINT ppt, long nFile, long nModule, ICanvas *pCanvas, long lColor ) { _ASSERTE( ppt != NULL ); _ASSERTE( pCanvas != NULL ); cIconBuffer *pBuffer; int nIndex; if( !findIcon( reinterpret_cast< HMODULE >( nModule ), *reinterpret_cast< DWORD* >( &nFile ), pBuffer, nIndex, lColor ) ) //Moputu - 05172002: Added long lColor to make icons with different colored borders unique. { if( nModule == 0 ) { if( !loadIcon( *reinterpret_cast< DWORD* >( &nFile ), pBuffer, nIndex, lColor ) ) return E_FAIL; } else { if( !loadIconResource( reinterpret_cast< HMODULE >( nModule ), *reinterpret_cast< DWORD* >( &nFile ), pBuffer, nIndex, lColor ) ) //Moputu - 05172002: Added long lColor to make icons with different colored borders unique. return E_FAIL; } } drawIcon( ppt, pCanvas, pBuffer, nIndex ); return S_OK; }