// 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 &current = 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 &param = m_clipping.top();

   if( m_rgn == NULL )
      m_rgn = ::CreateRectRgnIndirect( &param.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 &current = 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 &current = 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 &current = 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;
}