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>
748 lines
No EOL
20 KiB
C++
748 lines
No EOL
20 KiB
C++
// Canvas.cpp : Implementation of cCanvas
|
|
#include "stdafx.h"
|
|
#include "Inject.h"
|
|
#include "Canvas.h"
|
|
|
|
#include "Manager.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// cCanvas
|
|
|
|
cCanvas::~cCanvas()
|
|
{
|
|
_ASSERTE( m_hdc == NULL );
|
|
|
|
if( m_rgn != NULL )
|
|
::DeleteObject( m_rgn );
|
|
}
|
|
|
|
void cCanvas::testSurface()
|
|
{
|
|
if( m_pSurface.p == NULL )
|
|
cManager::_p->createSurface( &m_sz, &m_pSurface );
|
|
else if( m_pSurface->IsLost() != DD_OK )
|
|
m_pSurface->Restore();
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::PushClipRect(LPRECT prc, VARIANT_BOOL *pbVisible)
|
|
{
|
|
_ASSERTE( prc != NULL );
|
|
_ASSERTE( prc->right >= prc->left && prc->bottom >= prc->top );
|
|
_ASSERTE( pbVisible != NULL );
|
|
|
|
ClipParams ¤t = m_clipping.top();
|
|
|
|
if( !current.visible )
|
|
{
|
|
// Not visible means just push and hope for a pop
|
|
m_clipping.push( current );
|
|
return S_OK;
|
|
}
|
|
|
|
int nChildLeft = prc->left + current.window.left - current.org.x,
|
|
nChildTop = prc->top + current.window.top - current.org.y,
|
|
nChildWidth = prc->right - prc->left,
|
|
nChildHeight = prc->bottom - prc->top;
|
|
|
|
ClipParams p = {
|
|
{ nChildLeft, nChildTop, nChildLeft + nChildWidth, nChildTop + nChildHeight },
|
|
{ 0, 0 },
|
|
VARIANT_TRUE };
|
|
|
|
// Clip the four sides of the rectangle
|
|
if( p.window.left < current.window.left )
|
|
{
|
|
// Clip left edge
|
|
p.org.x += current.window.left - p.window.left;
|
|
p.window.left = current.window.left;
|
|
}
|
|
|
|
if( p.window.top < current.window.top )
|
|
{
|
|
// Clip top edge
|
|
p.org.y += current.window.top - p.window.top;
|
|
p.window.top = current.window.top;
|
|
}
|
|
|
|
if( p.window.right > current.window.right )
|
|
// Clip right edge
|
|
p.window.right = current.window.right;
|
|
|
|
if( p.window.bottom > current.window.bottom )
|
|
// Clip bottom edge
|
|
p.window.bottom = current.window.bottom;
|
|
|
|
// Check for clipping out of existance
|
|
if( p.window.left >= p.window.right || p.window.top >= p.window.bottom )
|
|
// This rectangle is no longer visible
|
|
p.visible = VARIANT_FALSE;
|
|
|
|
// Return the remainder of the rectangle
|
|
*pbVisible = p.visible;
|
|
|
|
m_clipping.push( p );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::PopClipRect()
|
|
{
|
|
_ASSERTE( m_clipping.size() > 1 );
|
|
|
|
m_clipping.pop();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::GetDC(HDC *pdc)
|
|
{
|
|
_ASSERTE( pdc != NULL );
|
|
|
|
testSurface();
|
|
|
|
if( m_hdc != NULL )
|
|
// Already checked out
|
|
return E_FAIL;
|
|
|
|
m_pSurface->GetDC( &m_hdc );
|
|
|
|
// Create a clipping region
|
|
ClipParams ¶m = m_clipping.top();
|
|
|
|
if( m_rgn == NULL )
|
|
m_rgn = ::CreateRectRgnIndirect( ¶m.window );
|
|
else
|
|
::SetRectRgn( m_rgn, param.window.left, param.window.top, param.window.right, param.window.bottom );
|
|
|
|
::SelectObject( m_hdc, m_rgn );
|
|
|
|
// Set the origin
|
|
::SetWindowOrgEx( m_hdc, -param.window.left + param.org.x, -param.window.top + param.org.y, NULL );
|
|
|
|
*pdc = m_hdc;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::ReleaseDC()
|
|
{
|
|
if( m_hdc == NULL )
|
|
return E_FAIL;
|
|
|
|
m_pSurface->ReleaseDC( m_hdc );
|
|
m_hdc = NULL;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::GetSurface(REFIID iid, void **ppvItf)
|
|
{
|
|
_ASSERTE( iid == IID_IDirectDrawSurface4 );
|
|
_ASSERTE( ppvItf != NULL );
|
|
|
|
testSurface();
|
|
|
|
return m_pSurface->QueryInterface( iid, ppvItf );
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::GetClipParams(ClipParams *pParams)
|
|
{
|
|
_ASSERTE( pParams != NULL );
|
|
|
|
*pParams = m_clipping.top();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::Fill(LPRECT prc, long nRGB)
|
|
{
|
|
_ASSERTE( prc != NULL );
|
|
_ASSERTE( prc->right > prc->left && prc->bottom > prc->top );
|
|
|
|
testSurface();
|
|
|
|
VARIANT_BOOL bVisible;
|
|
PushClipRect( prc, &bVisible );
|
|
|
|
if( bVisible )
|
|
{
|
|
DDBLTFX fx;
|
|
::memset( &fx, 0, sizeof( DDBLTFX ) );
|
|
|
|
fx.dwSize = sizeof( DDBLTFX );
|
|
|
|
DownMixRGB((BYTE)nRGB, (BYTE)(nRGB >> 8), (BYTE)(nRGB >> 16), (WORD *)&fx.dwFillColor);
|
|
|
|
m_pSurface->Blt( &m_clipping.top().window, NULL, NULL, DDBLT_COLORFILL, &fx );
|
|
}
|
|
|
|
PopClipRect();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::Frame(LPRECT prc, long nRGB)
|
|
{
|
|
_ASSERTE( prc != NULL );
|
|
_ASSERTE( prc->right > prc->left && prc->bottom > prc->top );
|
|
|
|
testSurface();
|
|
|
|
// TODO: Add your implementation code here
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::get_WasLost(VARIANT_BOOL *pVal)
|
|
{
|
|
_ASSERTE( pVal != NULL );
|
|
|
|
*pVal = VARIANT_FALSE;
|
|
|
|
if( m_pSurface.p != NULL )
|
|
{
|
|
if( m_pSurface->IsLost() != DD_OK )
|
|
*pVal = VARIANT_TRUE;
|
|
}
|
|
else
|
|
*pVal = VARIANT_TRUE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::get_Size(LPSIZE pVal)
|
|
{
|
|
_ASSERTE( pVal != NULL );
|
|
|
|
*pVal = m_sz;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::put_Size(LPSIZE newVal)
|
|
{
|
|
_ASSERTE( newVal->cx > 0 && newVal->cy > 0 );
|
|
_ASSERTE( m_clipping.size() == 1 );
|
|
|
|
if( m_sz.cx != newVal->cx || m_sz.cy != newVal->cy )
|
|
{
|
|
m_sz = *newVal;
|
|
if( m_pSurface.p )
|
|
// Next frame this'll be marked as lost
|
|
m_pSurface.Release();
|
|
|
|
// Reset the bounds in the root clip rectangle
|
|
ClipParams &clip = m_clipping.top();
|
|
clip.window.right = clip.window.left + newVal->cx;
|
|
clip.window.bottom = clip.window.top + newVal->cy;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::Blt(LPRECT prcSrc, ICanvas *pSrc, LPPOINT pptDest)
|
|
{
|
|
_ASSERTE( pSrc != NULL );
|
|
_ASSERTE( prcSrc != NULL );
|
|
_ASSERTE( prcSrc->right > prcSrc->left && prcSrc->bottom > prcSrc->top );
|
|
_ASSERTE( pptDest != NULL );
|
|
|
|
testSurface();
|
|
|
|
// Ok, first, make up the clip rect
|
|
RECT rc = { pptDest->x, pptDest->y, pptDest->x + ( prcSrc->right - prcSrc->left ),
|
|
pptDest->y + ( prcSrc->bottom - prcSrc->top ) };
|
|
VARIANT_BOOL bVisible;
|
|
|
|
PushClipRect( &rc, &bVisible );
|
|
if( bVisible )
|
|
{
|
|
CComPtr< IDirectDrawSurface4 > pSurf;
|
|
pSrc->GetSurface( IID_IDirectDrawSurface4, reinterpret_cast< void ** >( &pSurf ) );
|
|
|
|
_ASSERTE( pSurf.p != NULL );
|
|
_ASSERTE( pSurf->IsLost() == DD_OK );
|
|
|
|
// Calculate the metrics
|
|
#ifdef _DEBUG
|
|
SIZE sz;
|
|
pSrc->get_Size( &sz );
|
|
|
|
_ASSERTE( prcSrc->left >= 0 && prcSrc->top >= 0 && prcSrc->right <= sz.cx && prcSrc->bottom <= sz.cy );
|
|
#endif
|
|
|
|
ClipParams ¤t = m_clipping.top();
|
|
|
|
RECT rcSrcClipped = { prcSrc->left + current.org.x, prcSrc->top + current.org.y,
|
|
prcSrc->left + current.org.x + ( current.window.right - current.window.left ),
|
|
prcSrc->top + current.org.y + ( current.window.bottom - current.window.top ) };
|
|
|
|
HRESULT hRes = S_OK;
|
|
|
|
if ( sourceAlpha < 255) {
|
|
|
|
if( cManager::_p->m_eAlphaBlendMode == eAlphaBlendSoftware )
|
|
{
|
|
|
|
// Software alpha blending
|
|
// It's actually plausible to implement this entirely using D3D and thus get hardware acceleration
|
|
// Perhaps we should detect device caps and use a suitable method?
|
|
// This should work on every Decal configuration though (except bank switched video cards, but who has them? :)
|
|
|
|
//Lock and calculate metrics for destination
|
|
|
|
DDSURFACEDESC2 ddsd;
|
|
memset(&ddsd, 0, sizeof(ddsd));
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
|
|
int left = current.window.left;
|
|
int top = current.window.top;
|
|
int width = rcSrcClipped.right - rcSrcClipped.left;
|
|
int height = rcSrcClipped.bottom - rcSrcClipped.top;
|
|
|
|
if (FAILED(m_pSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL)))
|
|
_ASSERTE("Failed to destination lock surface!");
|
|
|
|
WORD *dest = (WORD *)ddsd.lpSurface;
|
|
|
|
int iPitch = ddsd.lPitch / 2;
|
|
int initialJump = (top * iPitch) + left;
|
|
int jump = (iPitch - (width + left)) + left + width;
|
|
|
|
//Lock and calculate metrics for source
|
|
|
|
DDSURFACEDESC2 srcddsd;
|
|
memset(&srcddsd, 0, sizeof(srcddsd));
|
|
srcddsd.dwSize = sizeof(srcddsd);
|
|
|
|
if (FAILED(pSurf->Lock(NULL, &srcddsd, DDLOCK_WAIT | DDLOCK_NOSYSLOCK, NULL)))
|
|
_ASSERTE("Failed to lock source surface!");
|
|
|
|
WORD *src = (WORD *)srcddsd.lpSurface;
|
|
|
|
//Do it
|
|
|
|
int iSrcPitch = srcddsd.lPitch / 2;
|
|
int alpha = sourceAlpha;
|
|
int ialpha = 255 - alpha;
|
|
|
|
WORD *srcLine = new WORD[width];
|
|
WORD *destLine = new WORD[width];
|
|
|
|
WORD sB, dB, sG, dG, sR, dR;
|
|
|
|
dest += initialJump;
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
// We'll read 1 line at a time - 80% of the speed decrease here is reading/writing against the surface
|
|
|
|
memcpy((void *)srcLine, src, width * 2);
|
|
memcpy((void *)destLine, dest, width * 2);
|
|
|
|
for (int x = 0; x < width; x++) {
|
|
// This method is very fast, but assumes a constant 128 alpha
|
|
// destLine[x] = ( (srcLine[x] & 0xF7DE) >> 1) + ( (destLine[x] & 0xF7DE) >> 1);
|
|
|
|
// Basically ((alpha * (src - dest) / MAXALPHA) + dest) for each component
|
|
// There's some significant room for MMX parrallelism here (~20% more FPS, methinks), but do we want to
|
|
// be writing ASM?
|
|
|
|
sB = srcLine[x] & ddsd.ddpfPixelFormat.dwBBitMask;
|
|
dB = destLine[x] & ddsd.ddpfPixelFormat.dwBBitMask;
|
|
sG = srcLine[x] & ddsd.ddpfPixelFormat.dwGBitMask;
|
|
dG = destLine[x] & ddsd.ddpfPixelFormat.dwGBitMask;
|
|
sR = srcLine[x] & ddsd.ddpfPixelFormat.dwRBitMask;
|
|
dR = destLine[x] & ddsd.ddpfPixelFormat.dwRBitMask;
|
|
|
|
destLine[x] = ddsd.ddpfPixelFormat.dwBBitMask & ((alpha * (sB - dB) >> 8) + dB) |
|
|
ddsd.ddpfPixelFormat.dwGBitMask & (((alpha * (sG - dG) >> 8) + dG)) |
|
|
ddsd.ddpfPixelFormat.dwRBitMask & (((alpha * (sR - dR) >> 8) + dR));
|
|
|
|
// The below is eversoslightly faster by assuming RGB 565 surface exposure. Some stupid old cards
|
|
// blow up however. Fiddle if you like, YMMV. I'm sticking with something that works :)
|
|
|
|
//sB = srcLine[x] & 0x1f;
|
|
//dB = destLine[x] & 0x1f;
|
|
//sG = (srcLine[x] >> 5) & 0x3f;
|
|
//dG = (destLine[x] >> 5) & 0x3f;
|
|
//sR = (srcLine[x] >> 11) & 0x1f;
|
|
//dR = (destLine[x] >> 11) & 0x1f;
|
|
|
|
//destLine[x] = ((alpha * (sB - dB) >> 8) + dB) |
|
|
// (((alpha * (sG - dG) >> 8) + dG) << 5) |
|
|
// (((alpha * (sR - dR) >> 8) + dR) << 11);*/
|
|
}
|
|
|
|
memcpy(dest, destLine, width * 2);
|
|
|
|
src += iSrcPitch;
|
|
dest += jump;
|
|
}
|
|
|
|
//Release
|
|
|
|
delete srcLine;
|
|
delete destLine;
|
|
|
|
if (FAILED(pSurf->Unlock(NULL)))
|
|
_ASSERTE("Failed to unlock source surface!");
|
|
|
|
if (FAILED(m_pSurface->Unlock(NULL)))
|
|
_ASSERTE("Failed to unlock destination surface!");
|
|
}
|
|
else if ((cManager::_p->m_eAlphaBlendMode == eAlphaBlendGDIPlus) && (AlphaBlendF!=NULL))
|
|
{
|
|
HDC hdcd;
|
|
HDC hdcs;
|
|
GetDC(&hdcd);
|
|
pSrc->GetDC(&hdcs);
|
|
|
|
hRes = AlphaBlendF(hdcd, current.org.x, current.org.y, rcSrcClipped.right-rcSrcClipped.left, rcSrcClipped.bottom-rcSrcClipped.top, hdcs, current.org.x, current.org.y, rcSrcClipped.right-rcSrcClipped.left, rcSrcClipped.bottom-rcSrcClipped.top, m_bf);
|
|
|
|
pSrc->ReleaseDC();
|
|
ReleaseDC();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hRes = m_pSurface->BltFast( current.window.left, current.window.top, pSurf, &rcSrcClipped, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT );
|
|
}
|
|
|
|
|
|
/* if(!SUCCEEDED(hRes))
|
|
{
|
|
POINT pt = { 0, 0 };
|
|
ClientToScreen(cManager::_p->m_hMain, &pt);
|
|
|
|
/*if((pt.x==0) || (pt.y==0))
|
|
MessageBox(0,"asd","asd",0);*/
|
|
//RECT rcd = {pt.x, pt.y, rcSrcClipped.right-rcSrcClipped.left, rcSrcClipped.bottom-rcSrcClipped.top};
|
|
//m_pSurface->Blt(&rcd,pSurf,&rcSrcClipped,DDBLT_WAIT,NULL);
|
|
// RECT rcd = {0, 0, 640, 480};
|
|
|
|
/* rcSrcClipped.left+=current.window.left+pt.x;
|
|
rcSrcClipped.right+=current.window.left+pt.x;
|
|
rcSrcClipped.top+=current.window.top+pt.y+28;
|
|
rcSrcClipped.bottom+=current.window.top+pt.y+28;
|
|
/*
|
|
DDBLTFX ddbltfx;
|
|
|
|
ddbltfx.dwSize=sizeof(ddbltfx);
|
|
ddbltfx.dwFillColor=5;
|
|
|
|
m_pSurface->Blt(&rcSrcClipped,NULL,NULL,DDBLT_COLORFILL,&ddbltfx);*/
|
|
|
|
/* CComPtr< ICanvas > pCan;
|
|
cManager::_p->GetPrimarySurface(&pCan);
|
|
CComPtr< IDirectDrawSurface4 > pDDS4;
|
|
pCan->GetSurface( IID_IDirectDrawSurface4, reinterpret_cast< void ** >( &pDDS4 ) );
|
|
|
|
// if(m_pSurface.p==pDDS4.p)
|
|
|
|
|
|
if(cManager::_p->m_lpSurface!=NULL)
|
|
{
|
|
MessageBeep(0);
|
|
DDSURFACEDESC2 ddesc;
|
|
ddesc.dwSize=sizeof(DDSURFACEDESC2);
|
|
|
|
pSurf->Lock(&rcSrcClipped, &ddesc, DDLOCK_SURFACEMEMORYPTR , NULL);
|
|
|
|
//m_pSurface->Blt(&rcSrcClipped,pSurf,NULL,DDBLT_KEYSRC | DDBLT_WAIT ,NULL);
|
|
memcpy(cManager::_p->m_lpSurface, ddesc.lpSurface, 1000);
|
|
|
|
pSurf->Unlock(&rcSrcClipped);
|
|
|
|
SetEvent(cManager::_p->m_hDrawSync);
|
|
|
|
}
|
|
|
|
//m_pSurface->Blt(&rcSrcClipped,pSurf,NULL,DDBLT_KEYSRC | DDBLT_WAIT ,NULL);
|
|
|
|
|
|
/* RECT rc;
|
|
::GetWindowRect( cManager::_p->m_hMain, &rc );*/
|
|
/*
|
|
HDC hdcd;
|
|
HDC hdcs;
|
|
m_pSurface->GetDC(&hdcd);
|
|
pSurf->GetDC(&hdcs);
|
|
BitBlt(hdcd, pt.x+current.window.left, pt.y+28+current.window.top, 332, current.window.bottom-current.window.top, hdcs, rcSrcClipped.left, rcSrcClipped.top, SRCCOPY);
|
|
pSurf->ReleaseDC(hdcs);
|
|
m_pSurface->ReleaseDC(hdcd);*/
|
|
|
|
/* hRes=0;
|
|
}
|
|
|
|
/*if(!SUCCEEDED(hRes))
|
|
SetEvent(cManager::_p->m_hDrawSync);*/
|
|
|
|
_ASSERTE( SUCCEEDED( hRes ) );
|
|
}
|
|
|
|
PopClipRect();
|
|
|
|
_ASSERTMEM( _CrtCheckMemory() );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::HitTest(LPPOINT ppt, VARIANT_BOOL *pbHit)
|
|
{
|
|
_ASSERTE( ppt != NULL );
|
|
_ASSERTE( pbHit != NULL );
|
|
|
|
// Assuming we're in screen coords
|
|
ClipParams &clip = m_clipping.top();
|
|
|
|
if( ppt->x >= clip.window.left && ppt->y >= clip.window.top &&
|
|
ppt->x <= clip.window.right && ppt->y <= clip.window.bottom )
|
|
{
|
|
*pbHit = VARIANT_TRUE;
|
|
}
|
|
else
|
|
*pbHit = VARIANT_FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::ToClient(LPPOINT pt)
|
|
{
|
|
_ASSERTE( pt != NULL );
|
|
|
|
ClipParams &clip = m_clipping.top();
|
|
pt->x -= clip.window.left - clip.org.x;
|
|
pt->y -= clip.window.top - clip.org.y;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::ToScreen(LPPOINT ppt)
|
|
{
|
|
_ASSERTE( ppt != NULL );
|
|
|
|
ClipParams &clip = m_clipping.top();
|
|
ppt->x += clip.window.left - clip.org.x;
|
|
ppt->y += clip.window.top - clip.org.y;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::OffsetOrg(LPPOINT ppt, VARIANT_BOOL *pbVisible)
|
|
{
|
|
_ASSERTE( ppt != NULL );
|
|
_ASSERTE( pbVisible != NULL );
|
|
_ASSERTE( m_clipping.size() != 1 );
|
|
|
|
ClipParams &clip = m_clipping.top();
|
|
clip.org.x += ppt->x;
|
|
clip.org.y += ppt->y;
|
|
|
|
*pbVisible = clip.visible;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::SetClipRect(LPRECT prc, VARIANT_BOOL *pbVisible)
|
|
{
|
|
_ASSERTE( prc != NULL );
|
|
_ASSERTE( prc->right >= prc->left && prc->bottom >= prc->top );
|
|
_ASSERTE( pbVisible != NULL );
|
|
_ASSERTE( m_clipping.size() != 1 );
|
|
|
|
ClipParams ¤t = m_clipping.top();
|
|
|
|
int nChildLeft = prc->left + current.window.left - current.org.x,
|
|
nChildTop = prc->top + current.window.top - current.org.y,
|
|
nChildWidth = prc->right - prc->left,
|
|
nChildHeight = prc->bottom - prc->top;
|
|
|
|
ClipParams p = {
|
|
{ nChildLeft, nChildTop, nChildLeft + nChildWidth, nChildTop + nChildHeight },
|
|
{ 0, 0 },
|
|
VARIANT_TRUE };
|
|
|
|
// Clip the four sides of the rectangle
|
|
if( p.window.left < current.window.left )
|
|
{
|
|
// Clip left edge
|
|
p.org.x += current.window.left - p.window.left;
|
|
p.window.left = current.window.left;
|
|
}
|
|
|
|
if( p.window.top < current.window.top )
|
|
{
|
|
// Clip top edge
|
|
p.org.y += current.window.top - p.window.top;
|
|
p.window.top = current.window.top;
|
|
}
|
|
|
|
if( p.window.right > current.window.right )
|
|
// Clip right edge
|
|
p.window.right = current.window.right;
|
|
|
|
if( p.window.bottom > current.window.bottom )
|
|
// Clip bottom edge
|
|
p.window.bottom = current.window.bottom;
|
|
|
|
// Check for clipping out of existance
|
|
if( p.window.left >= p.window.right || p.window.top >= p.window.bottom )
|
|
// This rectangle is no longer visible
|
|
p.visible = VARIANT_FALSE;
|
|
|
|
// Return the remainder of the rectangle
|
|
*pbVisible = p.visible;
|
|
|
|
m_clipping.top() = p;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::put_Alpha(long Alpha)
|
|
{
|
|
m_bf.SourceConstantAlpha = sourceAlpha = Alpha;
|
|
return S_OK;
|
|
}
|
|
|
|
// processMask - Support function for DownMixRGB
|
|
|
|
void cCanvas::processMask(WORD bitMask, WORD *loBit, WORD *bitCount) {
|
|
_ASSERTE(loBit);
|
|
_ASSERTE(bitCount);
|
|
|
|
WORD mask = 1;
|
|
|
|
for (*loBit = 0; *loBit < 16; (*loBit)++) {
|
|
if (bitMask & mask)
|
|
break;
|
|
|
|
mask <<= 1;
|
|
}
|
|
|
|
for (*bitCount = 1; *bitCount < 32; (*bitCount)++) {
|
|
mask <<= 1;
|
|
|
|
if (!(bitMask & mask))
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
// DownMixRGB - Returns a 16 bit RGB value suitable for this canvas from a standard R, G, B set
|
|
|
|
STDMETHODIMP cCanvas::DownMixRGB(WORD wRed, WORD wGreen, WORD wBlue, WORD *wDMRGB) {
|
|
_ASSERTE(wDMRGB);
|
|
|
|
if (wRBitCount == 0) {
|
|
// We've never obtained surface information before for this canvas
|
|
DDSURFACEDESC2 desc;
|
|
desc.dwSize = sizeof( DDSURFACEDESC2 );
|
|
|
|
if (FAILED(m_pSurface->GetSurfaceDesc(&desc)))
|
|
return S_FALSE;
|
|
|
|
processMask(desc.ddpfPixelFormat.dwRBitMask, &wRLoBit, &wRBitCount);
|
|
processMask(desc.ddpfPixelFormat.dwGBitMask, &wGLoBit, &wGBitCount);
|
|
processMask(desc.ddpfPixelFormat.dwBBitMask, &wBLoBit, &wBBitCount);
|
|
}
|
|
|
|
// Transparent color handling
|
|
if (wRed == 0 && wGreen == 255 && wBlue == 255) {
|
|
// We are a transparent colour - The downmix would've destroyed it
|
|
*wDMRGB = 0x07FF;
|
|
} else {
|
|
// Safe for a normal mix
|
|
*wDMRGB = ((wRed * (1 << wRBitCount)) / 256) << wRLoBit |
|
|
((wGreen * (1 << wGBitCount)) / 256) << wGLoBit |
|
|
((wBlue * (1 << wBBitCount)) / 256) << wBLoBit;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::GetDCLong(long *DC)
|
|
{
|
|
HDC pdc;
|
|
GetDC(&pdc);
|
|
*DC = reinterpret_cast< long >( pdc );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::SetTransparentColor(long TransColor)
|
|
{
|
|
unsigned short wDownmix;
|
|
|
|
DownMixRGB((BYTE)TransColor, (BYTE)(TransColor >> 8), (BYTE)(TransColor >> 16), &wDownmix );
|
|
|
|
_DDCOLORKEY colorkey;
|
|
|
|
colorkey.dwColorSpaceHighValue = wDownmix;
|
|
colorkey.dwColorSpaceLowValue = wDownmix;
|
|
|
|
m_pSurface->SetColorKey( DDCKEY_SRCBLT, &colorkey );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP cCanvas::StretchBlt(LPRECT prcSrc, ICanvas *pSrc, LPRECT prcDest)
|
|
{
|
|
_ASSERTE( pSrc != NULL );
|
|
_ASSERTE( prcSrc != NULL );
|
|
_ASSERTE( prcSrc->right > prcSrc->left && prcSrc->bottom > prcSrc->top );
|
|
//_ASSERTE( pptDest != NULL );
|
|
|
|
testSurface();
|
|
|
|
//RECT rc = { pptDest->x, pptDest->y, pptDest->x + ( prcSrc->right - prcSrc->left ), pptDest->y + ( prcSrc->bottom - prcSrc->top ) };
|
|
|
|
// Ok, first, make up the clip rect
|
|
RECT rc = { prcDest->left, prcDest->top, prcDest->right, prcDest->bottom };
|
|
|
|
VARIANT_BOOL bVisible = TRUE;
|
|
|
|
PushClipRect( &rc, &bVisible );
|
|
|
|
//if( bVisible )
|
|
{
|
|
CComPtr< IDirectDrawSurface4 > pSurf;
|
|
pSrc->GetSurface( IID_IDirectDrawSurface4, reinterpret_cast< void ** >( &pSurf ) );
|
|
|
|
_ASSERTE( pSurf.p != NULL );
|
|
_ASSERTE( pSurf->IsLost() == DD_OK );
|
|
|
|
// Calculate the metrics
|
|
#ifdef _DEBUG
|
|
SIZE sz;
|
|
pSrc->get_Size( &sz );
|
|
|
|
_ASSERTE( prcSrc->left >= 0 && prcSrc->top >= 0 && prcSrc->right <= sz.cx && prcSrc->bottom <= sz.cy );
|
|
#endif
|
|
|
|
ClipParams ¤t = m_clipping.top();
|
|
|
|
RECT rcSrcClipped = {
|
|
prcSrc->left,
|
|
prcSrc->top,
|
|
prcSrc->right,// + ( current.window.right - current.window.left ),
|
|
prcSrc->bottom// + ( current.window.bottom - current.window.top )
|
|
};
|
|
|
|
RECT rcDestClipped = {
|
|
prcDest->left + current.org.x + current.window.left,
|
|
prcDest->top + current.org.y + current.window.top,
|
|
prcDest->left + prcDest->right + current.org.x,
|
|
prcDest->top + prcDest->bottom + current.org.y
|
|
};
|
|
|
|
HRESULT hRes = m_pSurface->Blt( &rcDestClipped, pSurf, &rcSrcClipped, DDBLT_KEYSRC | DDBLT_WAIT, NULL );
|
|
|
|
_ASSERTE( SUCCEEDED( hRes ) );
|
|
}
|
|
|
|
PopClipRect();
|
|
|
|
_ASSERTMEM( _CrtCheckMemory() );
|
|
|
|
return S_OK;
|
|
} |