All 5 phases of the open-source Decal rebuild: Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil) Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters - Decal.Core, DecalControls, DecalRender, D3DService Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL Phase 4: DenAgent WinForms tray application Phase 5: WiX installer and build script 25 C# projects building with 0 errors. Native C++ projects require VS 2022 + Windows SDK (x86). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
291 lines
8.7 KiB
C++
291 lines
8.7 KiB
C++
// 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;
|
|
}
|